diff --git a/Makefile b/Makefile index b82f173757..f44eb2f49e 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ gen-mocks: ## Generate mocks mockgen -source=internal/store/events.go -destination=internal/mocks/mock_events.go -package=mocks mockgen -source=internal/store/process_measurements.go -destination=internal/mocks/mock_process_measurements.go -package=mocks mockgen -source=internal/store/process_disks.go -destination=internal/mocks/mock_process_disks.go -package=mocks + mockgen -source=internal/store/process_databases.go -destination=internal/mocks/mock_process_databases.go -package=mocks mockgen -source=internal/store/host_measurements.go -destination=internal/mocks/mock_host_measurements.go -package=mocks mockgen -source=internal/store/indexes.go -destination=internal/mocks/mock_indexes.go -package=mocks diff --git a/internal/cli/atlas_measurements.go b/internal/cli/atlas_measurements.go index e41fc4e123..75ccf573fd 100644 --- a/internal/cli/atlas_measurements.go +++ b/internal/cli/atlas_measurements.go @@ -49,6 +49,7 @@ func AtlasMeasurementsBuilder() *cobra.Command { } cmd.AddCommand(AtlasMeasurementsProcessBuilder()) cmd.AddCommand(AtlasMeasurementsDisksBuilder()) + cmd.AddCommand(AtlasMeasurementsDatabasesBuilder()) return cmd } diff --git a/internal/cli/atlas_measurements_databases.go b/internal/cli/atlas_measurements_databases.go new file mode 100644 index 0000000000..92d3265b0b --- /dev/null +++ b/internal/cli/atlas_measurements_databases.go @@ -0,0 +1,32 @@ +// 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/description" + "github.com/spf13/cobra" +) + +func AtlasMeasurementsDatabasesBuilder() *cobra.Command { + cmd := &cobra.Command{ + Use: "databases", + Aliases: []string{"database"}, + Short: description.Databases, + } + + cmd.AddCommand(AtlasMeasurementsDatabasesListBuilder()) + + return cmd +} diff --git a/internal/cli/atlas_measurements_databases_list.go b/internal/cli/atlas_measurements_databases_list.go new file mode 100644 index 0000000000..d6e89ce485 --- /dev/null +++ b/internal/cli/atlas_measurements_databases_list.go @@ -0,0 +1,81 @@ +// 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/description" + "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 atlasMeasurementsDatabasesListsOpts struct { + globalOpts + listOpts + host string + port int + store store.ProcessDatabaseLister +} + +func (opts *atlasMeasurementsDatabasesListsOpts) init() error { + if opts.ProjectID() == "" { + return errMissingProjectID + } + + var err error + opts.store, err = store.New() + return err +} + +func (opts *atlasMeasurementsDatabasesListsOpts) Run() error { + listOpts := opts.newListOptions() + result, err := opts.store.ProcessDatabases(opts.ProjectID(), opts.host, opts.port, listOpts) + + if err != nil { + return err + } + + return json.PrettyPrint(result) +} + +// mongocli atlas measurements process(es) disks lists host:port +func AtlasMeasurementsDatabasesListBuilder() *cobra.Command { + opts := &atlasMeasurementsDatabasesListsOpts{} + cmd := &cobra.Command{ + Use: "list", + Short: description.ListDatabases, + Aliases: []string{"ls"}, + Args: cobra.ExactArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + return opts.init() + }, + RunE: func(cmd *cobra.Command, args []string) error { + var err error + if opts.host, opts.port, err = GetHostNameAndPort(args[0]); err != nil { + return err + } + + return opts.Run() + }, + } + + cmd.Flags().IntVar(&opts.pageNum, flags.Page, 0, usage.Page) + cmd.Flags().IntVar(&opts.itemsPerPage, flags.Limit, 0, usage.Limit) + cmd.Flags().StringVar(&opts.projectID, flags.ProjectID, "", usage.ProjectID) + + return cmd +} diff --git a/internal/cli/atlas_measurements_databases_list_test.go b/internal/cli/atlas_measurements_databases_list_test.go new file mode 100644 index 0000000000..3ef279f031 --- /dev/null +++ b/internal/cli/atlas_measurements_databases_list_test.go @@ -0,0 +1,53 @@ +// 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 TestAtlasMeasurementsDatabasesListsOpts_Run(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mocks.NewMockProcessDatabaseLister(ctrl) + + defer ctrl.Finish() + + expected := fixtures.ProcessDatabases() + + listOpts := &atlasMeasurementsDatabasesListsOpts{ + host: "hard-00-00.mongodb.net", + port: 27017, + store: mockStore, + } + + hostName, port, err := GetHostNameAndPort("hard-00-00.mongodb.net:27017") + if err != nil { + t.Fatalf("Run() unexpected error: %v", err) + } + + opts := listOpts.newListOptions() + mockStore. + EXPECT().ProcessDatabases(listOpts.projectID, hostName, port, opts). + Return(expected, nil). + Times(1) + + err = listOpts.Run() + if err != nil { + t.Fatalf("Run() unexpected error: %v", err) + } +} diff --git a/internal/description/description.go b/internal/description/description.go index ef036b7c33..02ec57b114 100644 --- a/internal/description/description.go +++ b/internal/description/description.go @@ -56,6 +56,8 @@ A user’s roles apply to all the clusters in the project.` ProcessMeasurements = "Get measurements for a given host." Disks = "List available disks or disks measurements for a given host." ListDisks = "List available disks for a given host." + Databases = "List available databases or databases measurements for a given host." + ListDatabases = "List available databases for a given host." Whitelist = "Manage the IP whitelist for a project." CreateWhitelist = "Create an IP whitelist for a project." DeleteWhitelist = "Delete a database user for a project." diff --git a/internal/fixtures/measurements.go b/internal/fixtures/measurements.go index b4532c711c..5616af833b 100644 --- a/internal/fixtures/measurements.go +++ b/internal/fixtures/measurements.go @@ -39,6 +39,29 @@ func ProcessDisks() *atlas.ProcessDisksResponse { } } +func ProcessDatabases() *atlas.ProcessDatabasesResponse { + return &atlas.ProcessDatabasesResponse{ + Links: []*atlas.Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/12345678/processes/shard-00-00.mongodb.net:27017/databases", + }, + }, + Results: []*atlas.ProcessDatabase{ + { + Links: []*atlas.Link{ + { + Rel: "self", + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/12345678/processes/shard-00-00.mongodb.net:27017/databases/test", + }, + }, + DatabaseName: "test", + }, + }, + TotalCount: 1, + } +} + func ProcessMeasurements() *atlas.ProcessMeasurements { return &atlas.ProcessMeasurements{ End: "2017-08-22T20:31:14Z", diff --git a/internal/mocks/mock_process_databases.go b/internal/mocks/mock_process_databases.go new file mode 100644 index 0000000000..b29b912056 --- /dev/null +++ b/internal/mocks/mock_process_databases.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: internal/store/process_databases.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" +) + +// MockProcessDatabaseLister is a mock of ProcessDatabaseLister interface +type MockProcessDatabaseLister struct { + ctrl *gomock.Controller + recorder *MockProcessDatabaseListerMockRecorder +} + +// MockProcessDatabaseListerMockRecorder is the mock recorder for MockProcessDatabaseLister +type MockProcessDatabaseListerMockRecorder struct { + mock *MockProcessDatabaseLister +} + +// NewMockProcessDatabaseLister creates a new mock instance +func NewMockProcessDatabaseLister(ctrl *gomock.Controller) *MockProcessDatabaseLister { + mock := &MockProcessDatabaseLister{ctrl: ctrl} + mock.recorder = &MockProcessDatabaseListerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockProcessDatabaseLister) EXPECT() *MockProcessDatabaseListerMockRecorder { + return m.recorder +} + +// ProcessDatabases mocks base method +func (m *MockProcessDatabaseLister) ProcessDatabases(arg0, arg1 string, arg2 int, arg3 *mongodbatlas.ListOptions) (*mongodbatlas.ProcessDatabasesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ProcessDatabases", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*mongodbatlas.ProcessDatabasesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ProcessDatabases indicates an expected call of ProcessDatabases +func (mr *MockProcessDatabaseListerMockRecorder) ProcessDatabases(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessDatabases", reflect.TypeOf((*MockProcessDatabaseLister)(nil).ProcessDatabases), arg0, arg1, arg2, arg3) +} diff --git a/internal/store/process_databases.go b/internal/store/process_databases.go new file mode 100644 index 0000000000..485beec2dd --- /dev/null +++ b/internal/store/process_databases.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 ProcessDatabaseLister interface { + ProcessDatabases(string, string, int, *atlas.ListOptions) (*atlas.ProcessDatabasesResponse, error) +} + +// ProcessDatabases encapsulate the logic to manage different cloud providers +func (s *Store) ProcessDatabases(groupID, host string, port int, opts *atlas.ListOptions) (*atlas.ProcessDatabasesResponse, error) { + switch s.service { + case config.CloudService: + result, _, err := s.client.(*atlas.Client).ProcessDatabases.List(context.Background(), groupID, host, port, opts) + return result, err + default: + return nil, fmt.Errorf("unsupported service: %s", s.service) + } +}