diff --git a/Makefile b/Makefile index bf510d120e..218ef0c122 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ gen-mocks: ## Generate mocks mockgen -source=internal/store/continuous_jobs.go -destination=internal/mocks/mock_continuous_jobs.go -package=mocks mockgen -source=internal/store/agents.go -destination=internal/mocks/mock_agents.go -package=mocks mockgen -source=internal/store/checkpoints.go -destination=internal/mocks/mock_checkpoints.go -package=mocks + mockgen -source=internal/store/alerts.go -destination=internal/mocks/mock_alerts.go -package=mocks .PHONY: build build: ## Generate a binary in ./bin diff --git a/e2e/atlas_alerts_test.go b/e2e/atlas_alerts_test.go new file mode 100644 index 0000000000..b939f3c3fb --- /dev/null +++ b/e2e/atlas_alerts_test.go @@ -0,0 +1,84 @@ +// Copyright 2020 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. +// +build e2e + +package e2e_test + +import ( + "encoding/json" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas" +) + +const ( + closed = "CLOSED" + replication_oplog_window_running_out = "REPLICATION_OPLOG_WINDOW_RUNNING_OUT" +) + +func TestAtlasAlerts(t *testing.T) { + cliPath, err := filepath.Abs("../bin/mongocli") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + _, err = os.Stat(cliPath) + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + atlasEntity := "atlas" + alertsEntity := "alerts" + + t.Run("Describe", func(t *testing.T) { + alertID := "5e4d20ff5cc174527c22c606" + + cmd := exec.Command(cliPath, + atlasEntity, + alertsEntity, + "describe", + alertID, + ) + + cmd.Env = os.Environ() + resp, err := cmd.CombinedOutput() + + if err != nil { + t.Fatalf("unexpected error: %v, resp: %v", err, string(resp)) + } + + alert := mongodbatlas.Alert{} + err = json.Unmarshal(resp, &alert) + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if alert.ID != alertID { + t.Errorf("got=%#v\nwant=%#v\n", alert.ID, alertID) + } + + if alert.Status != closed { + t.Errorf("got=%#v\nwant=%#v\n", alert.Status, closed) + } + + if alert.EventTypeName != replication_oplog_window_running_out { + t.Errorf("got=%#v\nwant=%#v\n", alert.EventTypeName, replication_oplog_window_running_out) + } + + }) +} diff --git a/internal/cli/atlas_alerts.go b/internal/cli/atlas_alerts.go index 8e1ca74ed4..7d5ae71e03 100644 --- a/internal/cli/atlas_alerts.go +++ b/internal/cli/atlas_alerts.go @@ -26,6 +26,7 @@ func AtlasAlertsBuilder() *cobra.Command { } cmd.AddCommand(AtlasAlertConfigsBuilder()) + cmd.AddCommand(AtlasAlertsDescribeBuilder()) return cmd } diff --git a/internal/cli/atlas_alerts_describe.go b/internal/cli/atlas_alerts_describe.go new file mode 100644 index 0000000000..8f8ae3fb76 --- /dev/null +++ b/internal/cli/atlas_alerts_describe.go @@ -0,0 +1,71 @@ +// Copyright 2020 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 cli + +import ( + "github.com/mongodb/mongocli/internal/flags" + "github.com/mongodb/mongocli/internal/json" + "github.com/mongodb/mongocli/internal/store" + "github.com/mongodb/mongocli/internal/usage" + "github.com/spf13/cobra" +) + +type atlasAlertsDescribeOpts struct { + *globalOpts + alertID string + store store.AlertDescriber +} + +func (opts *atlasAlertsDescribeOpts) init() error { + if opts.ProjectID() == "" { + return errMissingProjectID + } + var err error + opts.store, err = store.New() + return err +} + +func (opts *atlasAlertsDescribeOpts) Run() error { + result, err := opts.store.Alert(opts.ProjectID(), opts.alertID) + + if err != nil { + return err + } + + return json.PrettyPrint(result) +} + +// mongocli atlas alerts describe alertID --projectId projectId +func AtlasAlertsDescribeBuilder() *cobra.Command { + opts := &atlasAlertsDescribeOpts{ + globalOpts: newGlobalOpts(), + } + cmd := &cobra.Command{ + Use: "describe [alertID]", + Short: "Describe an Atlas Alert.", + Args: cobra.ExactArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + return opts.init() + }, + RunE: func(cmd *cobra.Command, args []string) error { + opts.alertID = args[0] + return opts.Run() + }, + } + + cmd.Flags().StringVar(&opts.projectID, flags.ProjectID, "", usage.ProjectID) + + return cmd +} diff --git a/internal/cli/atlas_alerts_describe_test.go b/internal/cli/atlas_alerts_describe_test.go new file mode 100644 index 0000000000..738fbeb198 --- /dev/null +++ b/internal/cli/atlas_alerts_describe_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 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 cli + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/mongodb/mongocli/internal/fixtures" + "github.com/mongodb/mongocli/internal/mocks" +) + +func TestAtlasAlertsDescribe_Run(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mocks.NewMockAlertDescriber(ctrl) + + defer ctrl.Finish() + + expected := fixtures.Alert() + + describeOpts := &atlasAlertsDescribeOpts{ + globalOpts: newGlobalOpts(), + alertID: "533dc40ae4b00835ff81eaee", + store: mockStore, + } + + mockStore. + EXPECT(). + Alert(describeOpts.projectID, describeOpts.alertID). + Return(expected, nil). + Times(1) + + err := describeOpts.Run() + if err != nil { + t.Fatalf("Run() unexpected error: %v", err) + } +} diff --git a/internal/fixtures/alerts.go b/internal/fixtures/alerts.go new file mode 100644 index 0000000000..948356efb6 --- /dev/null +++ b/internal/fixtures/alerts.go @@ -0,0 +1,39 @@ +package fixtures + +import ( + atlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas" + "github.com/mwielbut/pointy" +) + +func Alert() *atlas.Alert { + return &atlas.Alert{ + ID: "533dc40ae4b00835ff81eaee", + GroupID: "535683b3794d371327b", + EventTypeName: "OUTSIDE_METRIC_THRESHOLD", + Created: "2016-08-23T20:26:50Z", + Updated: "2016-08-23T20:26:50Z", + Enabled: pointy.Bool(true), + Matchers: []atlas.Matcher{ + { + FieldName: "HOSTNAME_AND_PORT", + Operator: "EQUALS", + Value: "mongo.example.com:27017", + }, + }, + Notifications: []atlas.Notification{ + { + TypeName: "SMS", + IntervalMin: 5, + DelayMin: pointy.Int(0), + MobileNumber: "2343454567", + }, + }, + MetricThreshold: &atlas.MetricThreshold{ + MetricName: "ASSERT_REGULAR", + Operator: "LESS_THAN", + Threshold: 99.0, + Units: "RAW", + Mode: "AVERAGE", + }, + } +} diff --git a/internal/mocks/mock_alerts.go b/internal/mocks/mock_alerts.go new file mode 100644 index 0000000000..a641392aca --- /dev/null +++ b/internal/mocks/mock_alerts.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: internal/store/alerts.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + gomock "github.com/golang/mock/gomock" + mongodbatlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas" + reflect "reflect" +) + +// MockAlertDescriber is a mock of AlertDescriber interface +type MockAlertDescriber struct { + ctrl *gomock.Controller + recorder *MockAlertDescriberMockRecorder +} + +// MockAlertDescriberMockRecorder is the mock recorder for MockAlertDescriber +type MockAlertDescriberMockRecorder struct { + mock *MockAlertDescriber +} + +// NewMockAlertDescriber creates a new mock instance +func NewMockAlertDescriber(ctrl *gomock.Controller) *MockAlertDescriber { + mock := &MockAlertDescriber{ctrl: ctrl} + mock.recorder = &MockAlertDescriberMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAlertDescriber) EXPECT() *MockAlertDescriberMockRecorder { + return m.recorder +} + +// Alert mocks base method +func (m *MockAlertDescriber) Alert(arg0, arg1 string) (*mongodbatlas.Alert, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Alert", arg0, arg1) + ret0, _ := ret[0].(*mongodbatlas.Alert) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Alert indicates an expected call of Alert +func (mr *MockAlertDescriberMockRecorder) Alert(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Alert", reflect.TypeOf((*MockAlertDescriber)(nil).Alert), arg0, arg1) +} diff --git a/internal/store/alerts.go b/internal/store/alerts.go new file mode 100644 index 0000000000..b1f3ebb289 --- /dev/null +++ b/internal/store/alerts.go @@ -0,0 +1,38 @@ +// Copyright 2020 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 store + +import ( + "context" + "fmt" + + atlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas" + "github.com/mongodb/mongocli/internal/config" +) + +type AlertDescriber interface { + Alert(string, string) (*atlas.Alert, error) +} + +// Alert encapsulate the logic to manage different cloud providers +func (s *Store) Alert(projectID, alertID string) (*atlas.Alert, error) { + switch s.service { + case config.CloudService: + result, _, err := s.client.(*atlas.Client).Alerts.Get(context.Background(), projectID, alertID) + return result, err + default: + return nil, fmt.Errorf("unsupported service: %s", s.service) + } +}