From ddb57ca747956ba172dcc1f5a93c79b3ed0fcb2f Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Fri, 27 Mar 2020 15:13:07 +0000 Subject: [PATCH] CLOUDP-57848: Implement events resource in the atlas go client --- mongodbatlas/events.go | 166 +++++++++++++++++ mongodbatlas/events_test.go | 347 +++++++++++++++++++++++++++++++++++ mongodbatlas/mongodbatlas.go | 2 + 3 files changed, 515 insertions(+) create mode 100644 mongodbatlas/events.go create mode 100644 mongodbatlas/events_test.go diff --git a/mongodbatlas/events.go b/mongodbatlas/events.go new file mode 100644 index 000000000..11d9a0b81 --- /dev/null +++ b/mongodbatlas/events.go @@ -0,0 +1,166 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "net/http" +) + +const eventsPathProjects = "groups/%s/events" +const eventsPathOrganization = "orgs/%s/events" + +// EventsService is an interface for interfacing with the Events +// endpoints of the MongoDB Atlas API. +// See more: https://docs.atlas.mongodb.com/reference/api/events/ +type EventsService interface { + ListOrganizationEvents(context.Context, string, *EventListOptions) (*EventResponse, *Response, error) + GetOrganizationEvent(context.Context, string, string) (*Event, *Response, error) + ListProjectEvents(context.Context, string, *ListOptions) (*EventResponse, *Response, error) + GetProjectEvent(context.Context, string, string) (*Event, *Response, error) +} + +// EventsServiceOp handles communication with the Event related methods +// of the MongoDB Atlas API +type EventsServiceOp struct { + Client RequestDoer +} + +var _ EventsService = &EventsServiceOp{} + +// Event represents an event of the MongoDB Atlas API +type Event struct { + AlertID string `json:"alertId"` + AlertConfigID string `json:"alertConfigId"` + APIKeyID string `json:"apiKeyId,omitempty"` + Collection string `json:"collection,omitempty"` + Created string `json:"created"` + CurrentValue *CurrentValue `json:"currentValue,omitempty"` + Database string `json:"database,omitempty"` + EventTypeName string `json:"eventTypeName"` + GroupID string `json:"groupId,omitempty"` + Hostname string `json:"hostname"` + ID string `json:"id"` + InvoiceID string `json:"invoiceId,omitempty"` + IsGlobalAdmin bool `json:"isGlobalAdmin,omitempty"` + Links []*Link `json:"links"` + MetricName string `json:"metricName,omitempty"` + OpType string `json:"opType,omitempty"` + OrgID string `json:"orgId,omitempty"` + PaymentID string `json:"paymentId,omitempty"` + Port int `json:"Port,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + RemoteAddress string `json:"remoteAddress,omitempty"` + ReplicaSetName string `json:"replicaSetName,omitempty"` + ShardName string `json:"shardName,omitempty"` + TargetPublicKey string `json:"targetPublicKey,omitempty"` + TargetUsername string `json:"targetUsername,omitempty"` + TeamID string `json:"teamId,omitempty"` + UserID string `json:"userId,omitempty"` + Username string `json:"username,omitempty"` + WhitelistEntry string `json:"whitelistEntry,omitempty"` +} + +// EventResponse is the response from the EventsService.List. +type EventResponse struct { + Links []*Link `json:"links,omitempty"` + Results []*Event `json:"results,omitempty"` + TotalCount int `json:"totalCount,omitempty"` +} + +// EventListOptions specifies the optional parameters to the Event List methods. +type EventListOptions struct { + ListOptions + EventType string `url:"eventType,omitempty"` + MinDate string `url:"minDate,omitempty"` + MaxDate string `url:"maxDate,omitempty"` +} + +// ListOrganizationEvents lists all events in the organization associated to {ORG-ID}. +// See more: https://docs.atlas.mongodb.com/reference/api/events-orgs-get-all/ +func (s *EventsServiceOp) ListOrganizationEvents(ctx context.Context, orgID string, listOptions *EventListOptions) (*EventResponse, *Response, error) { + path := fmt.Sprintf(eventsPathOrganization, orgID) + + //Add query params from listOptions + 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(EventResponse) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, nil +} + +// GetOrganizationEvent gets the alert specified to {EVENT-ID} from the organization associated to {ORG-ID}. +// See more: https://docs.opsmanager.mongodb.com/current/reference/api/events/get-one-event-for-org/ +func (s *EventsServiceOp) GetOrganizationEvent(ctx context.Context, orgID string, eventID string) (*Event, *Response, error) { + basePath := fmt.Sprintf(eventsPathOrganization, orgID) + path := fmt.Sprintf("%s/%s", basePath, eventID) + + req, err := s.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(Event) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} + +// ListOrganizationEvents lists all events in the project associated to {PROJECT-ID}. +// See more: https://docs.opsmanager.mongodb.com/current/reference/api/events/get-all-events-for-project/ +func (s *EventsServiceOp) ListProjectEvents(ctx context.Context, projectID string, listOptions *ListOptions) (*EventResponse, *Response, error) { + path := fmt.Sprintf(eventsPathProjects, projectID) + + //Add query params from listOptions + 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(EventResponse) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, nil +} + +// GetOrganizationEvent gets the alert specified to {EVENT-ID} from the project associated to {PROJECT-ID}. +// See more: https://docs.opsmanager.mongodb.com/current/reference/api/events/get-one-event-for-project/ +func (s *EventsServiceOp) GetProjectEvent(ctx context.Context, projectID string, eventID string) (*Event, *Response, error) { + basePath := fmt.Sprintf(eventsPathProjects, projectID) + path := fmt.Sprintf("%s/%s", basePath, eventID) + + req, err := s.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(Event) + resp, err := s.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} diff --git a/mongodbatlas/events_test.go b/mongodbatlas/events_test.go new file mode 100644 index 000000000..b51f7093c --- /dev/null +++ b/mongodbatlas/events_test.go @@ -0,0 +1,347 @@ +package mongodbatlas + +import ( + "fmt" + "net/http" + "testing" + + "github.com/go-test/deep" +) + +func TestEvents_ListOrganizationEvents(t *testing.T) { + setup() + defer teardown() + + orgID := "5b478b3afc4625789ce616a3" + + mux.HandleFunc(fmt.Sprintf("/orgs/%s/events", orgID), 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/5b478b3afc4625789ce616a3/events?pageNum=1&itemsPerPage=100", + "rel": "self" + } + ], + "results": [ + { + "created": "2018-07-12T16:30:05Z", + "eventTypeName": "JOINED_TEAM", + "id": "b3ad04e680eef540be141abe", + "isGlobalAdmin": true, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b47820d80eef5264e12514a", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "203.0.113.22", + "targetUsername": "b.doe@example.com", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + }, + { + "created": "2018-07-09T21:14:40Z", + "eventTypeName": "GROUP_CREATED", + "groupId": "5b43d04087d9d6357de591a2", + "id": "5b478b3afc49d6357de591af", + "isGlobalAdmin": false, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b43d04087d9d6357de591af", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "192.0.2.88", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + } + ], + "totalCount": 2 + }`) + }) + + opts := &EventListOptions{} + + cluster, _, err := client.Events.ListOrganizationEvents(ctx, orgID, opts) + if err != nil { + t.Fatalf("Events.ListOrganizationEvents returned error: %v", err) + } + + expected := &EventResponse{ + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events?pageNum=1&itemsPerPage=100", + }, + }, + Results: []*Event{ + { + Created: "2018-07-12T16:30:05Z", + EventTypeName: "JOINED_TEAM", + ID: "b3ad04e680eef540be141abe", + IsGlobalAdmin: true, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b47820d80eef5264e12514a", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "203.0.113.22", + TargetUsername: "b.doe@example.com", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + }, + { + Created: "2018-07-09T21:14:40Z", + EventTypeName: "GROUP_CREATED", + GroupID: "5b43d04087d9d6357de591a2", + ID: "5b478b3afc49d6357de591af", + IsGlobalAdmin: false, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b43d04087d9d6357de591af", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "192.0.2.88", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + }, + }, + TotalCount: 2, + } + + if diff := deep.Equal(cluster, expected); diff != nil { + t.Error(diff) + } +} + +func TestEvents_GetOrganizationEvent(t *testing.T) { + setup() + defer teardown() + + orgID := "5b478b3afc4625789ce616a3" + eventID := "b3ad04e680eef540be141abe" + + mux.HandleFunc(fmt.Sprintf("/orgs/%s/events/%s", orgID, eventID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "created": "2018-07-12T16:30:05Z", + "eventTypeName": "JOINED_TEAM", + "id": "b3ad04e680eef540be141abe", + "isGlobalAdmin": true, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b47820d80eef5264e12514a", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "203.0.113.22", + "targetUsername": "b.doe@example.com", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + }`) + }) + + cluster, _, err := client.Events.GetOrganizationEvent(ctx, orgID, eventID) + if err != nil { + t.Fatalf("Events.GetOrganizationEvent returned error: %v", err) + } + + expected := &Event{ + Created: "2018-07-12T16:30:05Z", + EventTypeName: "JOINED_TEAM", + ID: "b3ad04e680eef540be141abe", + IsGlobalAdmin: true, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/orgs/5b478b3afc4625789ce616a3/events/5b47820d80eef5264e12514a", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "203.0.113.22", + TargetUsername: "b.doe@example.com", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + } + + if diff := deep.Equal(cluster, expected); diff != nil { + t.Error(diff) + } +} + +func TestEvents_ListProjectEvents(t *testing.T) { + setup() + defer teardown() + + groupID := "5b43d04087d9d6357de591a2" + + mux.HandleFunc(fmt.Sprintf("/groups/%s/events", groupID), 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/groups/5b43d04087d9d6357de591a2/events?pageNum=1&itemsPerPage=100", + "rel": "self" + } + ], + "results": [ + { + "created": "2018-07-12T16:30:05Z", + "eventTypeName": "JOINED_TEAM", + "id": "b3ad04e680eef540be141abe", + "isGlobalAdmin": true, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b47820d80eef5264e12514a", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "203.0.113.22", + "targetUsername": "b.doe@example.com", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + }, + { + "created": "2018-07-09T21:14:40Z", + "eventTypeName": "GROUP_CREATED", + "groupId": "5b43d04087d9d6357de591a2", + "id": "5b478b3afc49d6357de591af", + "isGlobalAdmin": false, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b43d04087d9d6357de591af", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "192.0.2.88", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + } + ], + "totalCount": 2 + }`) + }) + + opts := &ListOptions{} + + cluster, _, err := client.Events.ListProjectEvents(ctx, groupID, opts) + if err != nil { + t.Fatalf("Events.ListOrganizationEvents returned error: %v", err) + } + + expected := &EventResponse{ + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events?pageNum=1&itemsPerPage=100", + }, + }, + Results: []*Event{ + { + Created: "2018-07-12T16:30:05Z", + EventTypeName: "JOINED_TEAM", + ID: "b3ad04e680eef540be141abe", + IsGlobalAdmin: true, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b47820d80eef5264e12514a", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "203.0.113.22", + TargetUsername: "b.doe@example.com", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + }, + { + Created: "2018-07-09T21:14:40Z", + EventTypeName: "GROUP_CREATED", + GroupID: "5b43d04087d9d6357de591a2", + ID: "5b478b3afc49d6357de591af", + IsGlobalAdmin: false, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b43d04087d9d6357de591af", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "192.0.2.88", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + }, + }, + TotalCount: 2, + } + + if diff := deep.Equal(cluster, expected); diff != nil { + t.Error(diff) + } +} + +func TestEvents_GetProjectEvent(t *testing.T) { + setup() + defer teardown() + + groupID := "5b478b3afc4625789ce616a3" + eventID := "b3ad04e680eef540be141abe" + + mux.HandleFunc(fmt.Sprintf("/groups/%s/events/%s", groupID, eventID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "created": "2018-07-12T16:30:05Z", + "eventTypeName": "JOINED_TEAM", + "id": "b3ad04e680eef540be141abe", + "isGlobalAdmin": true, + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b43d04087d9d6357de591af", + "rel": "self" + } + ], + "orgId": "5b478b3afc4625789ce616a3", + "remoteAddress": "203.0.113.22", + "targetUsername": "b.doe@example.com", + "userId": "5898b79080eef53b3ad04e68", + "username": "j.doe@example.com" + }`) + }) + + cluster, _, err := client.Events.GetProjectEvent(ctx, groupID, eventID) + if err != nil { + t.Fatalf("Events.GetOrganizationEvent returned error: %v", err) + } + + expected := &Event{ + Created: "2018-07-12T16:30:05Z", + EventTypeName: "JOINED_TEAM", + ID: "b3ad04e680eef540be141abe", + IsGlobalAdmin: true, + Links: []*Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/5b43d04087d9d6357de591a2/events/5b43d04087d9d6357de591af", + }, + }, + OrgID: "5b478b3afc4625789ce616a3", + RemoteAddress: "203.0.113.22", + TargetUsername: "b.doe@example.com", + UserID: "5898b79080eef53b3ad04e68", + Username: "j.doe@example.com", + } + + if diff := deep.Equal(cluster, expected); diff != nil { + t.Error(diff) + } +} diff --git a/mongodbatlas/mongodbatlas.go b/mongodbatlas/mongodbatlas.go index 7d25ac983..a86f638d0 100644 --- a/mongodbatlas/mongodbatlas.go +++ b/mongodbatlas/mongodbatlas.go @@ -64,6 +64,7 @@ type Client struct { Checkpoints CheckpointsService Alerts AlertsService CloudProviderSnapshotBackupPolicies CloudProviderSnapshotBackupPoliciesService + Events EventsService onRequestCompleted RequestCompletionCallback } @@ -181,6 +182,7 @@ func NewClient(httpClient *http.Client) *Client { c.Checkpoints = &CheckpointsServiceOp{Client: c} c.Alerts = &AlertsServiceOp{Client: c} c.CloudProviderSnapshotBackupPolicies = &CloudProviderSnapshotBackupPoliciesServiceOp{Client: c} + c.Events = &EventsServiceOp{Client: c} return c }