Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addressing: add support for Address Map resource #1232

Merged
merged 8 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/1232.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
addressing: Add `Address Map` support
```
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,6 @@ This library is starting to ship with experimental improvements that are not yet
ready for production but will be introduced before the next major version. See
[experimental README](/docs/experimental.md) for full details.

# License
## License

BSD licensed. See the [LICENSE](LICENSE) file for details.
284 changes: 284 additions & 0 deletions addressing_address_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
package cloudflare

import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)

// AddressMap contains information about an address map.
type AddressMap struct {
ID string `json:"id"`
Description *string `json:"description,omitempty"`
DefaultSNI *string `json:"default_sni"`
Enabled *bool `json:"enabled"`
Deletable *bool `json:"can_delete"`
CanModifyIPs *bool `json:"can_modify_ips"`
Memberships []AddressMapMembership `json:"memberships"`
IPs []AddressMapIP `json:"ips"`
CreatedAt time.Time `json:"created_at"`
ModifiedAt time.Time `json:"modified_at"`
}

type AddressMapIP struct {
IP string `json:"ip"`
CreatedAt time.Time `json:"created_at"`
}

type AddressMapMembershipContainer struct {
Identifier string `json:"identifier"`
Kind AddressMapMembershipKind `json:"kind"`
}

type AddressMapMembership struct {
Identifier string `json:"identifier"`
Kind AddressMapMembershipKind `json:"kind"`
Deletable *bool `json:"can_delete"`
CreatedAt time.Time `json:"created_at"`
}

func (ammb *AddressMapMembershipContainer) URLFragment() string {
switch ammb.Kind {
case AddressMapMembershipAccount:
return fmt.Sprintf("accounts/%s", ammb.Identifier)
case AddressMapMembershipZone:
return fmt.Sprintf("zones/%s", ammb.Identifier)
default:
return fmt.Sprintf("%s/%s", ammb.Kind, ammb.Identifier)
}
}

type AddressMapMembershipKind string

const (
AddressMapMembershipZone AddressMapMembershipKind = "zone"
AddressMapMembershipAccount AddressMapMembershipKind = "account"
)

// ListAddressMapResponse contains a slice of address maps.
type ListAddressMapResponse struct {
Response
Result []AddressMap `json:"result"`
}

// GetAddressMapResponse contains a specific address map's API Response.
type GetAddressMapResponse struct {
Response
Result AddressMap `json:"result"`
}

// CreateAddressMapParams contains information about an address map to be created.
type CreateAddressMapParams struct {
Description *string `json:"description"`
Enabled *bool `json:"enabled"`
IPs []string `json:"ips"`
Memberships []AddressMapMembershipContainer `json:"memberships"`
}

// UpdateAddressMapParams contains information about an address map to be updated.
type UpdateAddressMapParams struct {
ID string `json:"id"`
Description *string `json:"description,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
DefaultSNI *string `json:"default_sni,omitempty"`
}

// AddressMapFilter contains filter parameters for finding a list of address maps.
type ListAddressMapsParams struct {
IP *string `url:"ip,omitempty"`
CIDR *string `url:"cidr,omitempty"`
}

// CreateIPAddressToAddressMapParams contains request parameters to add/remove IP address to/from an address map.
type CreateIPAddressToAddressMapParams struct {
// ID represents the target address map for adding the IP address.
ID string
// The IP address.
IP string
}

// CreateMembershipToAddressMapParams contains request parameters to add/remove membership from an address map.
type CreateMembershipToAddressMapParams struct {
// ID represents the target address map for adding the membershp.
ID string
Membership AddressMapMembershipContainer
}

type DeleteMembershipFromAddressMapParams struct {
// ID represents the target address map for removing the IP address.
ID string
Membership AddressMapMembershipContainer
}

type DeleteIPAddressFromAddressMapParams struct {
// ID represents the target address map for adding the membershp.
ID string
IP string
}

// ListAddressMaps lists all address maps owned by the account.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-list-address-maps
func (api *API) ListAddressMaps(ctx context.Context, rc *ResourceContainer, params ListAddressMapsParams) ([]AddressMap, error) {
if rc.Level != AccountRouteLevel {
return []AddressMap{}, ErrRequiredAccountLevelResourceContainer
}

uri := buildURI(fmt.Sprintf("/%s/addressing/address_maps", rc.URLFragment()), params)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return []AddressMap{}, err
}

result := ListAddressMapResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return []AddressMap{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return result.Result, nil
}

// CreateAddressMap creates a new address map under the account.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-create-address-map
func (api *API) CreateAddressMap(ctx context.Context, rc *ResourceContainer, params CreateAddressMapParams) (AddressMap, error) {
if rc.Level != AccountRouteLevel {
return AddressMap{}, ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps", rc.URLFragment())
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
if err != nil {
return AddressMap{}, err
}

result := GetAddressMapResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return AddressMap{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return result.Result, nil
}

// GetAddressMap returns a specific address map.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-address-map-details
func (api *API) GetAddressMap(ctx context.Context, rc *ResourceContainer, id string) (AddressMap, error) {
if rc.Level != AccountRouteLevel {
return AddressMap{}, ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s", rc.URLFragment(), id)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return AddressMap{}, err
}

result := GetAddressMapResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return AddressMap{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return result.Result, nil
}

// UpdateAddressMap modifies properties of an address map owned by the account.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-update-address-map
func (api *API) UpdateAddressMap(ctx context.Context, rc *ResourceContainer, params UpdateAddressMapParams) (AddressMap, error) {
if rc.Level != AccountRouteLevel {
return AddressMap{}, ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s", rc.URLFragment(), params.ID)
res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params)
if err != nil {
return AddressMap{}, err
}

result := GetAddressMapResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return AddressMap{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return result.Result, nil
}

// DeleteAddressMap deletes a particular address map owned by the account.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-delete-address-map
func (api *API) DeleteAddressMap(ctx context.Context, rc *ResourceContainer, id string) error {
if rc.Level != AccountRouteLevel {
return ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s", rc.URLFragment(), id)
_, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
return err
}

// CreateIPAddressToAddressMap adds an IP address from a prefix owned by the account to a particular address map.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-add-an-ip-to-an-address-map
func (api *API) CreateIPAddressToAddressMap(ctx context.Context, rc *ResourceContainer, params CreateIPAddressToAddressMapParams) error {
if rc.Level != AccountRouteLevel {
return ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s/ips/%s", rc.URLFragment(), params.ID, params.IP)
_, err := api.makeRequestContext(ctx, http.MethodPut, uri, nil)
return err
}

// DeleteIPAddressFromAddressMap removes an IP address from a particular address map.
//
// API reference: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-remove-an-ip-from-an-address-map
func (api *API) DeleteIPAddressFromAddressMap(ctx context.Context, rc *ResourceContainer, params DeleteIPAddressFromAddressMapParams) error {
if rc.Level != AccountRouteLevel {
return ErrRequiredAccountLevelResourceContainer
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s/ips/%s", rc.URLFragment(), params.ID, params.IP)
_, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
return err
}

// AddMembershipToAddressMap adds a zone/account as a member of a particular address map.
//
// API reference:
// - account: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-add-an-account-membership-to-an-address-map
// - zone: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-add-a-zone-membership-to-an-address-map
func (api *API) CreateMembershipToAddressMap(ctx context.Context, rc *ResourceContainer, params CreateMembershipToAddressMapParams) error {
if rc.Level != AccountRouteLevel {
return ErrRequiredAccountLevelResourceContainer
}

if params.Membership.Kind != AddressMapMembershipZone && params.Membership.Kind != AddressMapMembershipAccount {
return fmt.Errorf("requested membershp kind (%q) is not supported", params.Membership.Kind)
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s/%s", rc.URLFragment(), params.ID, params.Membership.URLFragment())
_, err := api.makeRequestContext(ctx, http.MethodPut, uri, nil)
return err
}

// DeleteMembershipFromAddressMap removes a zone/account as a member of a particular address map.
//
// API reference:
// - account: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-remove-an-account-membership-from-an-address-map
// - zone: https://developers.cloudflare.com/api/operations/ip-address-management-address-maps-remove-a-zone-membership-from-an-address-map
func (api *API) DeleteMembershipFromAddressMap(ctx context.Context, rc *ResourceContainer, params DeleteMembershipFromAddressMapParams) error {
if rc.Level != AccountRouteLevel {
return ErrRequiredAccountLevelResourceContainer
}

if params.Membership.Kind != AddressMapMembershipZone && params.Membership.Kind != AddressMapMembershipAccount {
return fmt.Errorf("requested membershp kind (%q) is not supported", params.Membership.Kind)
}

uri := fmt.Sprintf("/%s/addressing/address_maps/%s/%s", rc.URLFragment(), params.ID, params.Membership.URLFragment())
_, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
return err
}