diff --git a/go.mod b/go.mod index dede645ae8..39e8e01658 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/mattn/go-isatty v0.0.12 // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/mongodb/go-client-mongodb-atlas v0.1.4-0.20200312093748-8894c1fe3bb6 - github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312102454-e5173cc1a3b0 + github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312104623-fa9799b0cf65 github.com/pelletier/go-toml v1.6.0 // indirect github.com/spf13/afero v1.2.2 github.com/spf13/cast v1.3.1 // indirect diff --git a/go.sum b/go.sum index a4b99a2d24..7737cb74d3 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mongodb/go-client-mongodb-atlas v0.1.4-0.20200312093748-8894c1fe3bb6 h1:ukGCT8EiyLDm+dOJOgRqySvDjZJly5tUPUDZmQt+f0Y= github.com/mongodb/go-client-mongodb-atlas v0.1.4-0.20200312093748-8894c1fe3bb6/go.mod h1:LS8O0YLkA+sbtOb3fZLF10yY3tJM+1xATXMJ3oU35LU= -github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312102454-e5173cc1a3b0 h1:yOYbV6B8nH8jBoSKjITRE7TkU0xeAst7mAIt+JPFUlE= -github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312102454-e5173cc1a3b0/go.mod h1:G9iLP4YeC2TRpxjZRddP6wKjz2JbpAtX+MlKriO7TOU= +github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312104623-fa9799b0cf65 h1:zPiImkSeOsd+XF6ewOLYO/AnXM+P5AD6Mo8q0EDafIE= +github.com/mongodb/go-client-mongodb-ops-manager v0.0.2-0.20200312104623-fa9799b0cf65/go.mod h1:G9iLP4YeC2TRpxjZRddP6wKjz2JbpAtX+MlKriO7TOU= github.com/mwielbut/pointy v1.1.0 h1:U5/YEfoIkaGCHv0St3CgjduqXID4FNRoyZgLM1kY9vg= github.com/mwielbut/pointy v1.1.0/go.mod h1:MvvO+uMFj9T5DMda33HlvogsFBX7pWWKAkFIn4teYwY= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= diff --git a/internal/cli/cloud_manager_clusters_list.go b/internal/cli/cloud_manager_clusters_list.go index 9e6fa16245..c8f90a313c 100644 --- a/internal/cli/cloud_manager_clusters_list.go +++ b/internal/cli/cloud_manager_clusters_list.go @@ -15,6 +15,8 @@ package cli import ( + om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr" + "github.com/mongodb/mongocli/internal/config" "github.com/mongodb/mongocli/internal/convert" "github.com/mongodb/mongocli/internal/flags" "github.com/mongodb/mongocli/internal/json" @@ -23,36 +25,45 @@ import ( "github.com/spf13/cobra" ) -type cmClustersListOpts struct { +type cloudManagerClustersListOpts struct { *globalOpts - store store.AutomationGetter + store store.CloudManagerClustersLister } -func (opts *cmClustersListOpts) init() error { - if opts.ProjectID() == "" { - return errMissingProjectID - } - +func (opts *cloudManagerClustersListOpts) init() error { var err error opts.store, err = store.New() return err } -func (opts *cmClustersListOpts) Run() error { - result, err := opts.store.GetAutomationConfig(opts.ProjectID()) +func (opts *cloudManagerClustersListOpts) Run() error { + result, err := cloudManagerClustersListRun(opts) if err != nil { return err } - clusterConfigs := convert.FromAutomationConfig(result) + return json.PrettyPrint(result) +} - return json.PrettyPrint(clusterConfigs) +func cloudManagerClustersListRun(opts *cloudManagerClustersListOpts) (interface{}, error) { + var result interface{} + var err error + + if opts.projectID == "" && config.Service() == config.OpsManagerService { + result, err = opts.store.ListAllClustersProjects() + + } else { + var clusterConfigs *om.AutomationConfig + clusterConfigs, err = opts.store.GetAutomationConfig(opts.ProjectID()) + result = convert.FromAutomationConfig(clusterConfigs) + } + return result, err } // mongocli cloud-manager cluster(s) list --projectId projectId func CloudManagerClustersListBuilder() *cobra.Command { - opts := &cmClustersListOpts{ + opts := &cloudManagerClustersListOpts{ globalOpts: newGlobalOpts(), } cmd := &cobra.Command{ diff --git a/internal/cli/cloud_manager_clusters_list_test.go b/internal/cli/cloud_manager_clusters_list_test.go index 2dd79e5e86..3e1f34f49f 100644 --- a/internal/cli/cloud_manager_clusters_list_test.go +++ b/internal/cli/cloud_manager_clusters_list_test.go @@ -18,31 +18,57 @@ import ( "testing" "github.com/golang/mock/gomock" + "github.com/mongodb/mongocli/internal/config" "github.com/mongodb/mongocli/internal/fixtures" "github.com/mongodb/mongocli/internal/mocks" ) func TestCloudManagerClustersList_Run(t *testing.T) { ctrl := gomock.NewController(t) - mockStore := mocks.NewMockAutomationGetter(ctrl) + mockStore := mocks.NewMockCloudManagerClustersLister(ctrl) defer ctrl.Finish() - expected := fixtures.AutomationConfig() + t.Run("ProjectID is given", func(t *testing.T) { + expected := fixtures.AutomationConfig() - listOpts := &cmClustersListOpts{ - globalOpts: newGlobalOpts(), - store: mockStore, - } + listOpts := &cloudManagerClustersListOpts{ + globalOpts: newGlobalOpts(), + store: mockStore, + } - mockStore. - EXPECT(). - GetAutomationConfig(listOpts.projectID). - Return(expected, nil). - Times(1) + listOpts.projectID = "1" + mockStore. + EXPECT(). + GetAutomationConfig(listOpts.projectID). + Return(expected, nil). + Times(1) + + err := listOpts.Run() + if err != nil { + t.Fatalf("Run() unexpected error: %v", err) + } + + }) + + t.Run("No ProjectID is given", func(t *testing.T) { + expected := fixtures.AllClusters() + config.SetService(config.OpsManagerService) + mockStore. + EXPECT(). + ListAllClustersProjects(). + Return(expected, nil). + Times(1) + + listOpts := &cloudManagerClustersListOpts{ + globalOpts: newGlobalOpts(), + store: mockStore, + } + + err := listOpts.Run() + if err != nil { + t.Fatalf("Run() unexpected error: %v", err) + } + }) - err := listOpts.Run() - if err != nil { - t.Fatalf("Run() unexpected error: %v", err) - } } diff --git a/internal/fixtures/all_clusters.go b/internal/fixtures/all_clusters.go new file mode 100644 index 0000000000..6a574b402c --- /dev/null +++ b/internal/fixtures/all_clusters.go @@ -0,0 +1,112 @@ +// 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 fixtures + +import ( + atlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas" + om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr" +) + +func AllClusters() *om.AllClustersProjects { + return &om.AllClustersProjects{ + Links: []*atlas.Link{}, + Results: []*om.AllClustersProject{ + { + GroupName: "AtlasGroup1", + OrgName: "TestAtlasOrg1", + PlanType: "Atlas", + GroupID: "5e5fbc29e76c9a4be2ed3d39", + OrgID: "5e5fbc29e76c9a4be2ed3d36", + Clusters: []om.AllClustersCluster{ + { + ClusterID: "5e5fbc29e76c9a4be2ed3d4d", + Name: "AtlasCluster1", + Type: "sharded cluster", + Availability: "unavailable", + Versions: []string{"3.4.2"}, + BackupEnabled: true, + AuthEnabled: true, + SSLEnabled: true, + AlertCount: 0, + DataSizeBytes: 1000000, + NodeCount: 7, + }, + { + ClusterID: "5e5fbc29e76c9a4be2ed3d4f", + Name: "AtlasReplSet1", + Type: "replica set", + Availability: "dead", + Versions: []string{"3.4.1"}, + BackupEnabled: false, + AuthEnabled: true, + SSLEnabled: true, + AlertCount: 0, + DataSizeBytes: 1300000, + NodeCount: 2, + }, + }, + }, + { + GroupName: "CloudGroup1", + OrgName: "TestCloudOrg1", + PlanType: "Cloud Manager", + GroupID: "5e5fbc29e76c9a4be2ed3d38", + OrgID: "5e5fbc29e76c9a4be2ed3d34", + Tags: []string{"some tag 1", "some tag 2"}, + Clusters: []om.AllClustersCluster{ + { + ClusterID: "5e5fbc29e76c9a4be2ed3d42", + Name: "cluster1", + Type: "sharded cluster", + Availability: "warning", + Versions: []string{"3.4.1", "2.4.3"}, + BackupEnabled: true, + AuthEnabled: false, + SSLEnabled: false, + AlertCount: 0, + DataSizeBytes: 1000000, + NodeCount: 6, + }, + { + ClusterID: "5e5fbc29e76c9a4be2ed3d3c", + Name: "replica_set", + Type: "replica set", + Availability: "available", + Versions: []string{"3.4.1"}, + BackupEnabled: true, + AuthEnabled: true, + SSLEnabled: true, + AlertCount: 0, + DataSizeBytes: 500000, + NodeCount: 2, + }, + { + ClusterID: "da303f3fec69b2100bacf10dd9e6d5e0", + Name: "standalone:27017", + Type: "standalone", + Availability: "unavailable", + Versions: []string{"2.4.3"}, + BackupEnabled: false, + AuthEnabled: false, + SSLEnabled: true, + AlertCount: 0, + DataSizeBytes: 2000000, + NodeCount: 1, + }, + }, + }, + }, + TotalCount: 2, + } +} diff --git a/internal/mocks/mock_all_clusters_projects.go b/internal/mocks/mock_all_clusters_projects.go new file mode 100644 index 0000000000..08b7171111 --- /dev/null +++ b/internal/mocks/mock_all_clusters_projects.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: internal/store/all_clusters_projects.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + gomock "github.com/golang/mock/gomock" + opsmngr "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr" + reflect "reflect" +) + +// MockListAllClusters is a mock of ListAllClusters interface +type MockListAllClusters struct { + ctrl *gomock.Controller + recorder *MockListAllClustersMockRecorder +} + +// MockListAllClustersMockRecorder is the mock recorder for MockListAllClusters +type MockListAllClustersMockRecorder struct { + mock *MockListAllClusters +} + +// NewMockListAllClusters creates a new mock instance +func NewMockListAllClusters(ctrl *gomock.Controller) *MockListAllClusters { + mock := &MockListAllClusters{ctrl: ctrl} + mock.recorder = &MockListAllClustersMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockListAllClusters) EXPECT() *MockListAllClustersMockRecorder { + return m.recorder +} + +// ListAllClustersProjects mocks base method +func (m *MockListAllClusters) ListAllClustersProjects() (*opsmngr.AllClustersProjects, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListAllClustersProjects") + ret0, _ := ret[0].(*opsmngr.AllClustersProjects) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListAllClustersProjects indicates an expected call of ListAllClustersProjects +func (mr *MockListAllClustersMockRecorder) ListAllClustersProjects() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAllClustersProjects", reflect.TypeOf((*MockListAllClusters)(nil).ListAllClustersProjects)) +} diff --git a/internal/mocks/mock_automation.go b/internal/mocks/mock_automation.go index 89fbc55b27..a6aed5baed 100644 --- a/internal/mocks/mock_automation.go +++ b/internal/mocks/mock_automation.go @@ -85,6 +85,44 @@ func (mr *MockAutomationUpdaterMockRecorder) UpdateAutomationConfig(arg0, arg1 i return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAutomationConfig", reflect.TypeOf((*MockAutomationUpdater)(nil).UpdateAutomationConfig), arg0, arg1) } +// MockAllClusterLister is a mock of AllClusterLister interface +type MockAllClusterLister struct { + ctrl *gomock.Controller + recorder *MockAllClusterListerMockRecorder +} + +// MockAllClusterListerMockRecorder is the mock recorder for MockAllClusterLister +type MockAllClusterListerMockRecorder struct { + mock *MockAllClusterLister +} + +// NewMockAllClusterLister creates a new mock instance +func NewMockAllClusterLister(ctrl *gomock.Controller) *MockAllClusterLister { + mock := &MockAllClusterLister{ctrl: ctrl} + mock.recorder = &MockAllClusterListerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAllClusterLister) EXPECT() *MockAllClusterListerMockRecorder { + return m.recorder +} + +// ListAllClustersProjects mocks base method +func (m *MockAllClusterLister) ListAllClustersProjects() (*opsmngr.AllClustersProjects, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListAllClustersProjects") + ret0, _ := ret[0].(*opsmngr.AllClustersProjects) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListAllClustersProjects indicates an expected call of ListAllClustersProjects +func (mr *MockAllClusterListerMockRecorder) ListAllClustersProjects() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAllClustersProjects", reflect.TypeOf((*MockAllClusterLister)(nil).ListAllClustersProjects)) +} + // MockAutomationStore is a mock of AutomationStore interface type MockAutomationStore struct { ctrl *gomock.Controller @@ -136,3 +174,56 @@ func (mr *MockAutomationStoreMockRecorder) UpdateAutomationConfig(arg0, arg1 int mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAutomationConfig", reflect.TypeOf((*MockAutomationStore)(nil).UpdateAutomationConfig), arg0, arg1) } + +// MockCloudManagerClustersLister is a mock of CloudManagerClustersLister interface +type MockCloudManagerClustersLister struct { + ctrl *gomock.Controller + recorder *MockCloudManagerClustersListerMockRecorder +} + +// MockCloudManagerClustersListerMockRecorder is the mock recorder for MockCloudManagerClustersLister +type MockCloudManagerClustersListerMockRecorder struct { + mock *MockCloudManagerClustersLister +} + +// NewMockCloudManagerClustersLister creates a new mock instance +func NewMockCloudManagerClustersLister(ctrl *gomock.Controller) *MockCloudManagerClustersLister { + mock := &MockCloudManagerClustersLister{ctrl: ctrl} + mock.recorder = &MockCloudManagerClustersListerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockCloudManagerClustersLister) EXPECT() *MockCloudManagerClustersListerMockRecorder { + return m.recorder +} + +// GetAutomationConfig mocks base method +func (m *MockCloudManagerClustersLister) GetAutomationConfig(arg0 string) (*opsmngr.AutomationConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAutomationConfig", arg0) + ret0, _ := ret[0].(*opsmngr.AutomationConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAutomationConfig indicates an expected call of GetAutomationConfig +func (mr *MockCloudManagerClustersListerMockRecorder) GetAutomationConfig(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAutomationConfig", reflect.TypeOf((*MockCloudManagerClustersLister)(nil).GetAutomationConfig), arg0) +} + +// ListAllClustersProjects mocks base method +func (m *MockCloudManagerClustersLister) ListAllClustersProjects() (*opsmngr.AllClustersProjects, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListAllClustersProjects") + ret0, _ := ret[0].(*opsmngr.AllClustersProjects) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListAllClustersProjects indicates an expected call of ListAllClustersProjects +func (mr *MockCloudManagerClustersListerMockRecorder) ListAllClustersProjects() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAllClustersProjects", reflect.TypeOf((*MockCloudManagerClustersLister)(nil).ListAllClustersProjects)) +} diff --git a/internal/store/automation.go b/internal/store/automation.go index 3e8b7e3e10..58f2c257ea 100644 --- a/internal/store/automation.go +++ b/internal/store/automation.go @@ -30,11 +30,20 @@ type AutomationUpdater interface { UpdateAutomationConfig(string, *om.AutomationConfig) error } +type AllClusterLister interface { + ListAllClustersProjects() (*om.AllClustersProjects, error) +} + type AutomationStore interface { AutomationGetter AutomationUpdater } +type CloudManagerClustersLister interface { + AutomationGetter + AllClusterLister +} + // GetAutomationConfig encapsulate the logic to manage different cloud providers func (s *Store) GetAutomationConfig(projectID string) (*om.AutomationConfig, error) { switch s.service { @@ -56,3 +65,14 @@ func (s *Store) UpdateAutomationConfig(projectID string, automationConfig *om.Au return fmt.Errorf("unsupported service: %s", s.service) } } + +// ListAllClustersProjects encapsulate the logic to manage different cloud providers +func (s *Store) ListAllClustersProjects() (*om.AllClustersProjects, error) { + switch s.service { + case config.OpsManagerService, config.CloudManagerService: + result, _, err := s.client.(*om.Client).AllCusters.List(context.Background()) + return result, err + default: + return nil, fmt.Errorf("unsupported service: %s", s.service) + } +}