diff --git a/mongodbatlas/accesslist_api_keys.go b/mongodbatlas/accesslist_api_keys.go index 95c9b71ce..11e55b9b0 100644 --- a/mongodbatlas/accesslist_api_keys.go +++ b/mongodbatlas/accesslist_api_keys.go @@ -98,7 +98,7 @@ func (s *AccessListAPIKeysServiceOp) List(ctx context.Context, orgID, apiKeyID s return root, resp, nil } -// Get retrieve information on a single API Key access list entry using the unique identifier for the API Key and desired permitted address. +// Get retrieves information on a single API Key access list entry using the unique identifier for the API Key and desired permitted address. // // See more: https://docs.atlas.mongodb.com/reference/api/api-access-list/get-one-api-access-entry/ func (s *AccessListAPIKeysServiceOp) Get(ctx context.Context, orgID, apiKeyID, ipAddress string) (*AccessListAPIKey, *Response, error) { @@ -128,7 +128,7 @@ func (s *AccessListAPIKeysServiceOp) Get(ctx context.Context, orgID, apiKeyID, i return root, resp, err } -// Create one or more new access list entries for the specified API Key. +// Create creates one or more new access list entries for the specified API Key. // // See more: https://docs.atlas.mongodb.com/reference/api/api-access-list/create-api-access-entries/ func (s *AccessListAPIKeysServiceOp) Create(ctx context.Context, orgID, apiKeyID string, createRequest []*AccessListAPIKeysReq) (*AccessListAPIKeys, *Response, error) { diff --git a/mongodbatlas/clusters.go b/mongodbatlas/clusters.go index 298b1e864..268f60039 100644 --- a/mongodbatlas/clusters.go +++ b/mongodbatlas/clusters.go @@ -153,6 +153,7 @@ type Cluster struct { MongoURIUpdated string `json:"mongoURIUpdated,omitempty"` MongoURIWithOptions string `json:"mongoURIWithOptions,omitempty"` Name string `json:"name,omitempty"` + CreateDate string `json:"createDate,omitempty"` NumShards *int64 `json:"numShards,omitempty"` Paused *bool `json:"paused,omitempty"` PitEnabled *bool `json:"pitEnabled,omitempty"` @@ -164,6 +165,7 @@ type Cluster struct { SrvAddress string `json:"srvAddress,omitempty"` StateName string `json:"stateName,omitempty"` ConnectionStrings *ConnectionStrings `json:"connectionStrings,omitempty"` + Links []*Link `json:"links,omitempty"` } // ProcessArgs represents the advanced configuration options for the cluster. diff --git a/mongodbatlas/mongodbatlas.go b/mongodbatlas/mongodbatlas.go index 87bd4c7f0..d6ba4cc5d 100644 --- a/mongodbatlas/mongodbatlas.go +++ b/mongodbatlas/mongodbatlas.go @@ -137,6 +137,7 @@ type Client struct { DefaultMongoDBMajorVersion DefaultMongoDBMajorVersionService IPInfo IPInfoService AdvancedClusters AdvancedClustersService + ServerlessInstances ServerlessInstancesService onRequestCompleted RequestCompletionCallback } @@ -167,6 +168,9 @@ type ListOptions struct { // For paginated result sets, the number of results to include per page. ItemsPerPage int `url:"itemsPerPage,omitempty"` + + // Flag that indicates whether Atlas returns the totalCount parameter in the response body. + IncludeCount bool `url:"includeCount,omitempty"` } func (resp *Response) getCurrentPageLink() (*Link, error) { @@ -270,6 +274,7 @@ func NewClient(httpClient *http.Client) *Client { c.DefaultMongoDBMajorVersion = &DefaultMongoDBMajorVersionServiceOp{Client: c} c.IPInfo = &IPInfoServiceOp{Client: c} c.AdvancedClusters = &AdvancedClustersServiceOp{Client: c} + c.ServerlessInstances = &ServerlessInstancesServiceOp{Client: c} return c } diff --git a/mongodbatlas/serverless_instances.go b/mongodbatlas/serverless_instances.go new file mode 100644 index 000000000..3760d5c1b --- /dev/null +++ b/mongodbatlas/serverless_instances.go @@ -0,0 +1,162 @@ +// Copyright 2021 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongodbatlas + +import ( + "context" + "fmt" + "net/http" +) + +const serverlessInstancesPath = "api/atlas/v1.0/groups/%s/serverless" + +// ServerlessInstancesService is an interface for interfacing with the Serverless Instances endpoints of the MongoDB Atlas API. +// +// See more: https://docs.atlas.mongodb.com/reference/api/serverless/return-one-serverless-instance/ +type ServerlessInstancesService interface { + List(context.Context, string, *ListOptions) (*ClustersResponse, *Response, error) + Get(context.Context, string, string) (*Cluster, *Response, error) + Create(context.Context, string, *ServerlessCreateRequestParams) (*Cluster, *Response, error) + Delete(context.Context, string, string) (*Response, error) +} + +// ServerlessInstancesServiceOp handles communication with the Serverless Instances related methods of the MongoDB Atlas API. +type ServerlessInstancesServiceOp service + +var _ ServerlessInstancesService = &ServerlessInstancesServiceOp{} + +// ClustersResponse represents the response of ServerlessInstancesService.List. +type ClustersResponse struct { + Links []*Link `json:"links,omitempty"` + Results []*Cluster `json:"results,omitempty"` + TotalCount int `json:"totalCount,omitempty"` +} + +// ServerlessCreateRequestParams represents the Request Body Parameters of ServerlessInstancesService.Create. +type ServerlessCreateRequestParams struct { + Name string `json:"name,omitempty"` + ProviderSettings *ServerlessProviderSettings `json:"providerSettings,omitempty"` +} + +// ServerlessProviderSettings represents the Provider Settings of serverless instances. +type ServerlessProviderSettings struct { + BackingProviderName string `json:"backingProviderName,omitempty"` + ProviderName string `json:"providerName,omitempty"` + RegionName string `json:"regionName,omitempty"` +} + +// List gets all serverless instances in the specified project. +// +// See more: https://docs.atlas.mongodb.com/reference/api/serverless/return-all-serverless-instances/ +func (s *ServerlessInstancesServiceOp) List(ctx context.Context, projectID string, listOptions *ListOptions) (*ClustersResponse, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + + path := fmt.Sprintf(serverlessInstancesPath, projectID) + path, err := setListOptions(path, listOptions) + if err != nil { + return nil, nil, err + } + + req, err := s.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(ClustersResponse) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, nil +} + +// Get retrieves one serverless instance in the specified project. +// +// See more: https://docs.atlas.mongodb.com/reference/api/serverless/return-one-serverless-instance/ +func (s *ServerlessInstancesServiceOp) Get(ctx context.Context, projectID, instanceName string) (*Cluster, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + + if instanceName == "" { + return nil, nil, NewArgError("instanceName", "must be set") + } + + basePath := fmt.Sprintf(serverlessInstancesPath, projectID) + path := fmt.Sprintf("%s/%s", basePath, instanceName) + + req, err := s.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(Cluster) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} + +// Create creates one serverless instance in the specified project. +// +// See more: https://docs.atlas.mongodb.com/reference/api/serverless/create-one-serverless-instance/ +func (s *ServerlessInstancesServiceOp) Create(ctx context.Context, projectID string, bodyParams *ServerlessCreateRequestParams) (*Cluster, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + + path := fmt.Sprintf(serverlessInstancesPath, projectID) + + req, err := s.Client.NewRequest(ctx, http.MethodPost, path, bodyParams) + if err != nil { + return nil, nil, err + } + + root := new(Cluster) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} + +// Delete deletes one serverless instance in the specified project. +// +// See more: https://docs.atlas.mongodb.com/reference/api/serverless/remove-one-serverless-instance/ +func (s *ServerlessInstancesServiceOp) Delete(ctx context.Context, projectID, instanceName string) (*Response, error) { + if projectID == "" { + return nil, NewArgError("projectID", "must be set") + } + if instanceName == "" { + return nil, NewArgError("instanceName", "must be set") + } + + basePath := fmt.Sprintf(serverlessInstancesPath, projectID) + path := fmt.Sprintf("%s/%s", basePath, instanceName) + + req, err := s.Client.NewRequest(ctx, http.MethodDelete, path, nil) + if err != nil { + return nil, err + } + resp, err := s.Client.Do(ctx, req, nil) + + return resp, err +} diff --git a/mongodbatlas/serverless_instances_test.go b/mongodbatlas/serverless_instances_test.go new file mode 100644 index 000000000..260b91e27 --- /dev/null +++ b/mongodbatlas/serverless_instances_test.go @@ -0,0 +1,267 @@ +// Copyright 2021 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongodbatlas + +import ( + "fmt" + "net/http" + "testing" + + "github.com/go-test/deep" +) + +const ( + projectID = "PROJECT-ID" + id = "1" +) + +func TestServerlessInstances_List(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/"+serverlessInstancesPath, projectID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/orgs/599c510c80eef518f3b63fe1/serverless/5c49e72980eef544a218f8f8/accessList/?pretty=true&pageNum=1&itemsPerPage=100", + "rel": "self" + } + ], + "results": [{ + "connectionStrings": { + "standardSrv": "mongodb+srv://instance1.example.com" + }, + "createDate": "2021-06-25T21:32:06Z", + "groupId" : "PROJECT-ID", + "id": "1", + "links": [ { + "href": "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + "rel": "self" + } ], + "mongoDBVersion": "5.0.0", + "name": "test1", + "providerSettings": { + "providerName": "SERVERLESS", + "backingProviderName": "AWS", + "regionName": "US_EAST_1" + }, + "stateName": "IDLE" + },{ + "connectionStrings": { + "standardSrv" : "mongodb+srv://instance1.example.com" + }, + "createDate": "2021-06-25T21:32:06Z", + "groupId": "PROJECT-ID", + "id": "2", + "links": [{ + "href": "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + "rel": "self" + }], + "mongoDBVersion": "5.0.0", + "name": "test2", + "providerSettings": { + "providerName": "SERVERLESS", + "backingProviderName": "AWS", + "regionName": "US_EAST_1" + }, + "stateName": "IDLE" + }], + "totalCount": 2 + }`) + }) + + serverlessInstances, _, err := client.ServerlessInstances.List(ctx, projectID, nil) + if err != nil { + t.Fatalf("ServerlessInstances.List returned error: %v", err) + } + + expected := &ClustersResponse{ + Links: []*Link{ + { + Href: "https://cloud.mongodb.com/api/atlas/v1.0/orgs/599c510c80eef518f3b63fe1/serverless/5c49e72980eef544a218f8f8/accessList/?pretty=true&pageNum=1&itemsPerPage=100", + Rel: "self", + }, + }, + Results: []*Cluster{ + { + ID: id, + GroupID: projectID, + MongoDBVersion: "5.0.0", + Name: "test1", + ProviderSettings: &ProviderSettings{RegionName: "US_EAST_1", BackingProviderName: "AWS", ProviderName: "SERVERLESS"}, + StateName: "IDLE", + ConnectionStrings: &ConnectionStrings{StandardSrv: "mongodb+srv://instance1.example.com"}, + CreateDate: "2021-06-25T21:32:06Z", + Links: []*Link{ + { + Rel: "self", + Href: "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + }, + }, + }, + { + ID: "2", + GroupID: projectID, + MongoDBVersion: "5.0.0", + Name: "test2", + ProviderSettings: &ProviderSettings{RegionName: "US_EAST_1", BackingProviderName: "AWS", ProviderName: "SERVERLESS"}, + StateName: "IDLE", + ConnectionStrings: &ConnectionStrings{StandardSrv: "mongodb+srv://instance1.example.com"}, + CreateDate: "2021-06-25T21:32:06Z", + Links: []*Link{ + { + Rel: "self", + Href: "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + }, + }, + }, + }, + TotalCount: 2, + } + + if diff := deep.Equal(serverlessInstances, expected); diff != nil { + t.Error(diff) + } +} + +func TestServerlessInstances_Get(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/"+serverlessInstancesPath+"/%s", projectID, id), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "connectionStrings": { + "standardSrv": "mongodb+srv://instance1.example.com" + }, + "createDate": "2021-06-25T21:32:06Z", + "groupId" : "PROJECT-ID", + "id": "1", + "links": [ { + "href": "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + "rel": "self" + } ], + "mongoDBVersion": "5.0.0", + "name": "test1", + "providerSettings": { + "providerName": "SERVERLESS", + "backingProviderName": "AWS", + "regionName": "US_EAST_1" + }, + "stateName": "IDLE" + }`) + }) + + serverlessInstance, _, err := client.ServerlessInstances.Get(ctx, projectID, id) + if err != nil { + t.Fatalf("ServerlessInstances.Get returned error: %v", err) + } + + expected := &Cluster{ + ID: id, + GroupID: projectID, + MongoDBVersion: "5.0.0", + Name: "test1", + ProviderSettings: &ProviderSettings{RegionName: "US_EAST_1", BackingProviderName: "AWS", ProviderName: "SERVERLESS"}, + StateName: "IDLE", + ConnectionStrings: &ConnectionStrings{StandardSrv: "mongodb+srv://instance1.example.com"}, + CreateDate: "2021-06-25T21:32:06Z", + Links: []*Link{ + { + Rel: "self", + Href: "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + }, + }, + } + + if diff := deep.Equal(serverlessInstance, expected); diff != nil { + t.Error(diff) + } +} + +func TestServerlessInstances_Create(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/"+serverlessInstancesPath, projectID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPost) + fmt.Fprint(w, `{ + "connectionStrings": { + "standardSrv": "mongodb+srv://instance1.example.com" + }, + "createDate": "2021-06-25T21:32:06Z", + "groupId" : "PROJECT-ID", + "id": "1", + "links": [ { + "href": "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + "rel": "self" + } ], + "mongoDBVersion": "5.0.0", + "name": "test1", + "providerSettings": { + "providerName": "SERVERLESS", + "backingProviderName": "AWS", + "regionName": "US_EAST_1" + }, + "stateName": "IDLE" + }`) + }) + + bodyParam := &ServerlessCreateRequestParams{ + Name: "test1", + ProviderSettings: &ServerlessProviderSettings{RegionName: "US_EAST_1", BackingProviderName: "AWS", ProviderName: "SERVERLESS"}, + } + + serverlessInstance, _, err := client.ServerlessInstances.Create(ctx, projectID, bodyParam) + if err != nil { + t.Fatalf("ServerlessInstances.Get returned error: %v", err) + } + + expected := &Cluster{ + ID: id, + GroupID: projectID, + MongoDBVersion: "5.0.0", + Name: "test1", + ProviderSettings: &ProviderSettings{RegionName: "US_EAST_1", BackingProviderName: "AWS", ProviderName: "SERVERLESS"}, + StateName: "IDLE", + ConnectionStrings: &ConnectionStrings{StandardSrv: "mongodb+srv://instance1.example.com"}, + CreateDate: "2021-06-25T21:32:06Z", + Links: []*Link{ + { + Rel: "self", + Href: "http://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/serverless/{instanceName1}", + }, + }, + } + + if diff := deep.Equal(serverlessInstance, expected); diff != nil { + t.Error(diff) + } +} + +func TestServerlessInstances_Delete(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/"+serverlessInstancesPath+"/%s", projectID, id), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodDelete) + }) + + _, err := client.ServerlessInstances.Delete(ctx, projectID, id) + if err != nil { + t.Fatalf("ServerlessInstances.Delete returned error: %v", err) + } +}