diff --git a/account_availability.go b/account_availability.go new file mode 100644 index 000000000..9a846415c --- /dev/null +++ b/account_availability.go @@ -0,0 +1,62 @@ +package linodego + +import ( + "context" + "fmt" + "net/url" + + "github.com/go-resty/resty/v2" +) + +// AccountAvailability returns the resources information in a region which are NOT available to an account. +type AccountAvailability struct { + // region id + Region string `json:"region"` + + // the unavailable resources in a region to the customer + Unavailable []string `json:"unavailable"` +} + +// AccountAvailabilityPagedResponse represents a paginated Account Availability API response +type AccountAvailabilityPagedResponse struct { + *PageOptions + Data []AccountAvailability `json:"data"` +} + +// endpoint gets the endpoint URL for AccountAvailability +func (AccountAvailabilityPagedResponse) endpoint(_ ...any) string { + return "/account/availability" +} + +func (resp *AccountAvailabilityPagedResponse) castResult(r *resty.Request, e string) (int, int, error) { + res, err := coupleAPIErrors(r.SetResult(AccountAvailabilityPagedResponse{}).Get(e)) + if err != nil { + return 0, 0, err + } + castedRes := res.Result().(*AccountAvailabilityPagedResponse) + resp.Data = append(resp.Data, castedRes.Data...) + return castedRes.Pages, castedRes.Results, nil +} + +// ListAccountAvailabilities lists all available regions and the resources which are NOT available to the account. +func (c *Client) ListAccountAvailabilities(ctx context.Context, opts *ListOptions) ([]AccountAvailability, error) { + response := AccountAvailabilityPagedResponse{} + err := c.listHelper(ctx, &response, opts) + if err != nil { + return nil, err + } + return response.Data, nil +} + +// GetAccountAvailability gets the unavailable resources in a region to the customer. +func (c *Client) GetAccountAvailability(ctx context.Context, regionID string) (*AccountAvailability, error) { + req := c.R(ctx).SetResult(&AccountAvailability{}) + regionID = url.PathEscape(regionID) + b := fmt.Sprintf("account/availability/%s", regionID) + r, err := coupleAPIErrors(req.Get(b)) + if err != nil { + return nil, err + } + + return r.Result().(*AccountAvailability), nil +} diff --git a/test/integration/account_availability_test.go b/test/integration/account_availability_test.go new file mode 100644 index 000000000..4a308ccdd --- /dev/null +++ b/test/integration/account_availability_test.go @@ -0,0 +1,38 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" +) + +func TestAccountAvailability_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestAccountAvailability_List") + defer teardown() + + availabilities, err := client.ListAccountAvailabilities(context.Background(), &linodego.ListOptions{}) + if err != nil { + t.Errorf("Error getting Account Availabilities, expected struct, got error %v", err) + } + + if len(availabilities) == 0 { + t.Errorf("Expected to see account availabilities returned.") + } +} + +func TestAccountAvailability_Get(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestAccountAvailability_Get") + defer teardown() + + regionID := "us-east" + availability, err := client.GetAccountAvailability(context.Background(), regionID) + + if err != nil { + t.Errorf("Error getting Account Availability, expected struct, got error %v", err) + } + + if availability.Region != regionID { + t.Errorf("expected region ID to be %s; got %s", regionID, availability.Region) + } +} diff --git a/test/integration/fixtures/TestAccountAvailability_Get.yaml b/test/integration/fixtures/TestAccountAvailability_Get.yaml new file mode 100644 index 000000000..1aa0ba929 --- /dev/null +++ b/test/integration/fixtures/TestAccountAvailability_Get.yaml @@ -0,0 +1,60 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/account/availability/us-east + method: GET + response: + body: '{"region": "us-east", "unavailable": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Content-Length: + - "40" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "1200" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestAccountAvailability_List.yaml b/test/integration/fixtures/TestAccountAvailability_List.yaml new file mode 100644 index 000000000..062232507 --- /dev/null +++ b/test/integration/fixtures/TestAccountAvailability_List.yaml @@ -0,0 +1,65 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/account/availability + method: GET + response: + body: '{"data": [{"region": "ap-west", "unavailable": []}, {"region": "ca-central", + "unavailable": []}, {"region": "ap-southeast", "unavailable": []}, {"region": + "us-central", "unavailable": []}, {"region": "us-west", "unavailable": []}, + {"region": "us-southeast", "unavailable": []}, {"region": "us-east", "unavailable": + []}, {"region": "eu-west", "unavailable": []}, {"region": "ap-south", "unavailable": + []}, {"region": "eu-central", "unavailable": []}, {"region": "ap-northeast", + "unavailable": []}], "page": 1, "pages": 1, "results": 11}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Accept-Encoding + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "1200" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: ""