From 7661fb038413e13f932484af47ca1ee2c1df6d16 Mon Sep 17 00:00:00 2001 From: Ray Milkey Date: Thu, 7 Jan 2021 08:14:02 -0800 Subject: [PATCH] Remove CLI code - moved into the CLI repo --- pkg/cli/compactchanges.go | 54 ------- pkg/cli/completion.go | 24 --- pkg/cli/crud.go | 59 ------- pkg/cli/devicechanges.go | 130 --------------- pkg/cli/devicechanges_test.go | 149 ------------------ pkg/cli/load.go | 248 ----------------------------- pkg/cli/mockclients_test.go | 279 --------------------------------- pkg/cli/models.go | 155 ------------------ pkg/cli/models_test.go | 114 -------------- pkg/cli/networkchanges.go | 118 -------------- pkg/cli/networkchanges_test.go | 166 -------------------- pkg/cli/opstate.go | 93 ----------- pkg/cli/opstate_test.go | 95 ----------- pkg/cli/rollback.go | 54 ------- pkg/cli/rollback_test.go | 39 ----- pkg/cli/root.go | 57 ------- pkg/cli/root_test.go | 94 ----------- pkg/cli/snapshot.go | 118 -------------- 18 files changed, 2046 deletions(-) delete mode 100644 pkg/cli/compactchanges.go delete mode 100644 pkg/cli/completion.go delete mode 100644 pkg/cli/crud.go delete mode 100644 pkg/cli/devicechanges.go delete mode 100644 pkg/cli/devicechanges_test.go delete mode 100644 pkg/cli/load.go delete mode 100644 pkg/cli/mockclients_test.go delete mode 100644 pkg/cli/models.go delete mode 100644 pkg/cli/models_test.go delete mode 100644 pkg/cli/networkchanges.go delete mode 100644 pkg/cli/networkchanges_test.go delete mode 100644 pkg/cli/opstate.go delete mode 100644 pkg/cli/opstate_test.go delete mode 100644 pkg/cli/rollback.go delete mode 100644 pkg/cli/rollback_test.go delete mode 100644 pkg/cli/root.go delete mode 100644 pkg/cli/root_test.go delete mode 100644 pkg/cli/snapshot.go diff --git a/pkg/cli/compactchanges.go b/pkg/cli/compactchanges.go deleted file mode 100644 index 395fa1c2e..000000000 --- a/pkg/cli/compactchanges.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "github.com/onosproject/onos-api/go/onos/config/admin" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" -) - -func getCompactCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "compact-changes", - Short: "Takes a snapshot of network and device changes", - Args: cobra.NoArgs, - RunE: runCompactCommand, - } - cmd.Flags().DurationP("retention-period", "r", 0, "the period for which to retain all changes") - return cmd -} - -func runCompactCommand(cmd *cobra.Command, args []string) error { - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := admin.CreateConfigAdminServiceClient(clientConnection) - - retentionPeriod, _ := cmd.Flags().GetDuration("retention-period") - request := &admin.CompactChangesRequest{} - if retentionPeriod != 0 { - request.RetentionPeriod = &retentionPeriod - } - _, err := client.CompactChanges(context.Background(), request) - if err != nil { - return err - } - cli.Output("Completed compaction\n") - return nil -} diff --git a/pkg/cli/completion.go b/pkg/cli/completion.go deleted file mode 100644 index 4e0db147d..000000000 --- a/pkg/cli/completion.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 - -const bashCompletion = ` -# add stuff later -` - -// GetBashCompletion returns the bash completion script -func GetBashCompletion() string { - return bashCompletion -} diff --git a/pkg/cli/crud.go b/pkg/cli/crud.go deleted file mode 100644 index 19206d6e0..000000000 --- a/pkg/cli/crud.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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/spf13/cobra" - "text/template" -) - -func getGetCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "get {device-changes,network-changes,plugins,opstate,snapshots} [args]", - Short: "Get config resources", - } - cmd.AddCommand(getListNetworkChangesCommand()) - cmd.AddCommand(getListDeviceChangesCommand()) - cmd.AddCommand(getGetPluginsCommand()) - cmd.AddCommand(getGetOpstateCommand()) - cmd.AddCommand(getListSnapshotsCommand()) - return cmd -} - -func getAddCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "add {plugin} [args]", - Short: "Add a config resource", - } - cmd.AddCommand(getAddPluginCommand()) - return cmd -} - -func getWatchCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "watch resource [args]", - Short: "Watch for updates to a config resource type", - } - cmd.AddCommand(getWatchDeviceChangesCommand()) - cmd.AddCommand(getWatchNetworkChangesCommand()) - cmd.AddCommand(getWatchOpstateCommand()) - cmd.AddCommand(getWatchSnapshotsCommand()) - return cmd -} - -var funcMapChanges = template.FuncMap{ - "wrappath": wrapPath, - "valuetostring": valueToSstring, -} diff --git a/pkg/cli/devicechanges.go b/pkg/cli/devicechanges.go deleted file mode 100644 index d0f3b5f60..000000000 --- a/pkg/cli/devicechanges.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "fmt" - devicechange "github.com/onosproject/onos-api/go/onos/config/change/device" - "github.com/onosproject/onos-api/go/onos/config/device" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" - "io" - "strings" - "text/template" -) - -const deviceChangeTemplate = changeHeaderFormat + - "\t{{.NetworkChange.ID}}\t{{.NetworkChange.Index}}\t{{.Change.DeviceID}}\t{{.Change.DeviceVersion}}\n" + - "{{range .Change.Values}}" + typedValueFormat + "{{end}}\n" - -func getWatchDeviceChangesCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "device-changes ", - Short: "Watch for changes on a device with updates", - Args: cobra.ExactArgs(1), - RunE: runWatchDeviceChangesCommand, - } - cmd.Flags().StringP("version", "v", "", "an optional version") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func getListDeviceChangesCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "device-changes ", - Short: "List current changes on a device", - Args: cobra.ExactArgs(1), - RunE: runListDeviceChangesCommand, - } - cmd.Flags().StringP("version", "v", "", "device version") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func runWatchDeviceChangesCommand(cmd *cobra.Command, args []string) error { - return deviceChangesCommand(cmd, true, args) -} - -func runListDeviceChangesCommand(cmd *cobra.Command, args []string) error { - return deviceChangesCommand(cmd, false, args) -} - -func deviceChangesCommand(cmd *cobra.Command, subscribe bool, args []string) error { - id := args[0] // Argument is mandatory - version, _ := cmd.Flags().GetString("version") - noHeaders, _ := cmd.Flags().GetBool("no-headers") - - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := diags.CreateChangeServiceClient(clientConnection) - changesReq := diags.ListDeviceChangeRequest{ - Subscribe: subscribe, - DeviceID: device.ID(id), - DeviceVersion: device.Version(version), - } - - var tmplChanges *template.Template - tmplChanges, _ = template.New("device").Funcs(funcMapChanges).Parse(deviceChangeTemplate) - - stream, err := client.ListDeviceChanges(context.Background(), &changesReq) - if err != nil { - return err - } - if !noHeaders { - cli.GetOutput().Write([]byte(changeHeader)) - } - for { - in, err := stream.Recv() - if err == io.EOF { - return nil - } - if err != nil { - return err - } - _ = tmplChanges.Execute(cli.GetOutput(), in.Change) - } -} - -func wrapPath(path string, lineLen int, tabs int) string { - over := len(path) % lineLen - linesC := len(path) / lineLen - var wrapped []string - if over > 0 { - wrapped = make([]string, linesC+1) - } else { - wrapped = make([]string, linesC) - } - var i int - for i = 0; i < linesC; i++ { - wrapped[i] = path[i*lineLen : i*lineLen+lineLen] - } - if over > 0 { - overFmt := fmt.Sprintf("%s-%ds", "%", lineLen) - wrapped[linesC] = fmt.Sprintf(overFmt, path[linesC*lineLen:]) - } - - tabsArr := make([]string, tabs+1) - sep := fmt.Sprintf("\n%s ", strings.Join(tabsArr, "\t")) - return strings.Join(wrapped, sep) -} - -func valueToSstring(cv devicechange.TypedValue) string { - return cv.ValueToString() -} diff --git a/pkg/cli/devicechanges_test.go b/pkg/cli/devicechanges_test.go deleted file mode 100644 index 5dbf73987..000000000 --- a/pkg/cli/devicechanges_test.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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. - -// Unit tests for watch and list device-changes CLI -package cli - -import ( - "bytes" - "fmt" - changetypes "github.com/onosproject/onos-api/go/onos/config/change" - devicechange "github.com/onosproject/onos-api/go/onos/config/change/device" - networkchange "github.com/onosproject/onos-api/go/onos/config/change/network" - "github.com/onosproject/onos-api/go/onos/config/device" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "gotest.tools/assert" - "io" - "strings" - "testing" - "time" -) - -var deviceChanges []devicechange.DeviceChange -var networkChanges []networkchange.NetworkChange - -func generateDeviceChangeData(count int) { - deviceChanges = make([]devicechange.DeviceChange, count) - now := time.Now() - for cfgIdx := range deviceChanges { - deviceID := fmt.Sprintf("device-%d", cfgIdx) - - deviceChanges[cfgIdx] = devicechange.DeviceChange{ - ID: devicechange.ID(deviceID), - Index: devicechange.Index(cfgIdx), - Revision: 0, - NetworkChange: devicechange.NetworkChangeRef{ - ID: "network-1", - Index: 0, - }, - Change: &devicechange.Change{ - DeviceID: device.ID(deviceID), - DeviceVersion: "1.0.0", - Values: []*devicechange.ChangeValue{ - { - Path: "/aa/bb/cc", - Value: devicechange.NewTypedValueString("Test1"), - Removed: false, - }, - { - Path: "/aa/bb/dd", - Value: devicechange.NewTypedValueString("Test2"), - Removed: false, - }, - }, - }, - Status: changetypes.Status{ - Phase: changetypes.Phase(cfgIdx % 2), - State: changetypes.State(cfgIdx % 4), - Reason: changetypes.Reason(cfgIdx % 2), - Message: "Test", - }, - Created: now, - Updated: now, - } - } -} - -var nextDevChIndex = 0 - -func recvDeviceChangesMock() (*diags.ListDeviceChangeResponse, error) { - if nextDevChIndex < len(deviceChanges) { - netw := deviceChanges[nextDevChIndex] - nextDevChIndex++ - - return &diags.ListDeviceChangeResponse{ - Change: &netw, - }, nil - } - return nil, io.EOF -} - -func Test_WatchDeviceChanges(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - generateDeviceChangeData(4) - generateNetworkChangeData(4) - - configsClient := MockChangeServiceListDeviceChangesClient{ - recvFn: recvDeviceChangesMock, - } - - setUpMockClients(MockClientsConfig{ - listDeviceChangesClient: &configsClient, - }) - - deviceChangesCmd := getWatchDeviceChangesCommand() - err := deviceChangesCmd.RunE(deviceChangesCmd, []string{"device-1"}) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Equal(t, strings.Count(output, "Test2"), len(deviceChanges)) - -} - -var nextListDevChIndex = 0 - -func recvListDeviceChangesMock() (*diags.ListDeviceChangeResponse, error) { - if nextListDevChIndex < len(deviceChanges) { - netw := deviceChanges[nextListDevChIndex] - nextListDevChIndex++ - - return &diags.ListDeviceChangeResponse{ - Change: &netw, - }, nil - } - return nil, io.EOF -} - -func Test_ListDeviceChanges(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - generateDeviceChangeData(4) - generateNetworkChangeData(4) - - configsClient := MockChangeServiceListDeviceChangesClient{ - recvFn: recvListDeviceChangesMock, - } - - setUpMockClients(MockClientsConfig{ - listDeviceChangesClient: &configsClient, - }) - - deviceChangesCmd := getWatchDeviceChangesCommand() - err := deviceChangesCmd.RunE(deviceChangesCmd, []string{"device-1"}) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Equal(t, strings.Count(output, "Test2"), len(deviceChanges)) - -} diff --git a/pkg/cli/load.go b/pkg/cli/load.go deleted file mode 100644 index 3075f5d8c..000000000 --- a/pkg/cli/load.go +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "crypto/tls" - "fmt" - "github.com/golang/protobuf/proto" - "github.com/onosproject/onos-config/pkg/config/load" - "github.com/onosproject/onos-config/pkg/northbound/gnmi" - "github.com/onosproject/onos-config/pkg/southbound" - "github.com/onosproject/onos-lib-go/pkg/certs" - "github.com/openconfig/gnmi/client" - gpb "github.com/openconfig/gnmi/proto/gnmi" - "github.com/openconfig/gnmi/proto/gnmi_ext" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "io/ioutil" - "path/filepath" - "time" -) - -const ( - addressFlag = "service-address" - addressKey = "service-address" - tlsCertPathFlag = "tls-cert-path" - tlsKeyPathFlag = "tls-key-path" - noTLSFlag = "no-tls" -) - -func getLoadCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "load {type}", - Short: "Load configuration from a file", - } - cmd.AddCommand(getYamlCommand()) - cmd.AddCommand(getProtoCommand()) - cmd.PersistentFlags().StringP("name", "n", "", "Optional name for gNMI Set") - return cmd -} - -func getYamlCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "yaml {file(s)} [args]", - Short: "Load configuration from one or more YAML files", - Args: cobra.MinimumNArgs(1), - RunE: runLoadYamlCommand, - } - return cmd -} - -func runLoadYamlCommand(cmd *cobra.Command, args []string) error { - gnmiName, _ := cmd.Flags().GetString("name") - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - dest := &client.Destination{ - Addrs: []string{getAddress(cmd)}, - } - if !noTLS(cmd) { - dest.TLS = &tls.Config{ - InsecureSkipVerify: true, - } - cert := getCertPath(cmd) - key := getKeyPath(cmd) - dest.TLS.RootCAs, _ = certs.GetCertPoolDefault() - var clientCerts tls.Certificate - var err error - if cert == "" && key == "" { - clientCerts, _ = tls.X509KeyPair([]byte(certs.DefaultClientCrt), []byte(certs.DefaultClientKey)) - } else { - clientCerts, err = tls.LoadX509KeyPair(cert, key) - if err != nil { - return err - } - } - dest.TLS.Certificates = []tls.Certificate{clientCerts} - } - - gnmiClient, err := southbound.GnmiClientFactory(ctx, *dest) - if err != nil { - fmt.Printf("Error loading gnmiClient at %v\n", dest.Addrs) - return err - } - - for idx, arg := range args { - fmt.Printf("Loading config %s\n", arg) - load.Clear() - configGnmi, err := load.GetConfigGnmi(arg) - if err != nil { - fmt.Printf("Error loading %s\n", arg) - return err - } - gnmiSetRequest := load.ToGnmiSetRequest(&configGnmi) - - if gnmiName != "" { - gnmiNameExt := gnmiName - if len(args) > 1 { - gnmiNameExt = fmt.Sprintf("%s-%d", gnmiName, idx) - } - ext100Name := gnmi_ext.Extension_RegisteredExt{ - RegisteredExt: &gnmi_ext.RegisteredExtension{ - Id: gnmi.GnmiExtensionNetwkChangeID, - Msg: []byte(gnmiNameExt), - }, - } - gnmiSetRequest.Extension = append(gnmiSetRequest.Extension, &gnmi_ext.Extension{ - Ext: &ext100Name, - }) - } - - resp, err := gnmiClient.Set(ctx, gnmiSetRequest) - if err != nil { - fmt.Printf("Error running set on %s \n%v\n", arg, configGnmi.SetRequest) - return err - } - if len(resp.Response) == 0 { - return fmt.Errorf("empty response to gNMI Set %v", resp) - } - fmt.Printf("Load succeeded %v\n", resp.GetExtension()) - } - - return nil -} - -func getProtoCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "proto {file(s)} [args]", - Short: "Load configuration from one or more gNMI proto files", - Args: cobra.MinimumNArgs(1), - RunE: runLoadProtoCommand, - } - return cmd -} - -func runLoadProtoCommand(cmd *cobra.Command, args []string) error { - gnmiName, _ := cmd.Flags().GetString("name") - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - dest := &client.Destination{ - Addrs: []string{getAddress(cmd)}, - } - if !noTLS(cmd) { - dest.TLS = &tls.Config{ - InsecureSkipVerify: true, - } - cert := getCertPath(cmd) - key := getKeyPath(cmd) - dest.TLS.RootCAs, _ = certs.GetCertPoolDefault() - var clientCerts tls.Certificate - var err error - if cert == "" && key == "" { - clientCerts, _ = tls.X509KeyPair([]byte(certs.DefaultClientCrt), []byte(certs.DefaultClientKey)) - } else { - clientCerts, err = tls.LoadX509KeyPair(cert, key) - if err != nil { - return err - } - } - dest.TLS.Certificates = []tls.Certificate{clientCerts} - } - - gnmiClient, err := southbound.GnmiClientFactory(ctx, *dest) - if err != nil { - fmt.Printf("Error loading gnmiClient at %v\n", dest.Addrs) - return err - } - - for idx, arg := range args { - gnmiSetRequest := &gpb.SetRequest{} - abspath, err := filepath.Abs(arg) - if err != nil { - return fmt.Errorf("cannot get absolute path of %s: %v", arg, err) - } - protobuf, err := ioutil.ReadFile(abspath) - if err != nil { - return fmt.Errorf("unable to read protobuf file %s: %v", arg, err) - } - if err := proto.UnmarshalText(string(protobuf), gnmiSetRequest); err != nil { - return fmt.Errorf("unable to parse gnmi.GetRequest from %q : %v", arg, err) - } - - if gnmiName != "" { - gnmiNameExt := gnmiName - if len(args) > 1 { - gnmiNameExt = fmt.Sprintf("%s-%d", gnmiName, idx) - } - ext100Name := gnmi_ext.Extension_RegisteredExt{ - RegisteredExt: &gnmi_ext.RegisteredExtension{ - Id: gnmi.GnmiExtensionNetwkChangeID, - Msg: []byte(gnmiNameExt), - }, - } - gnmiSetRequest.Extension = append(gnmiSetRequest.Extension, &gnmi_ext.Extension{ - Ext: &ext100Name, - }) - } - - resp, err := gnmiClient.Set(ctx, gnmiSetRequest) - if err != nil { - fmt.Printf("Error running set on %s \n%v\n", arg, gnmiSetRequest) - return err - } - if len(resp.Response) == 0 { - return fmt.Errorf("empty response to gNMI Set %v", resp) - } - fmt.Printf("Load succeeded %v\n", resp.GetExtension()) - } - - return nil -} - -func getAddress(cmd *cobra.Command) string { - address, _ := cmd.Flags().GetString(addressFlag) - if address == "" { - return viper.GetString(addressKey) - } - return address -} - -func getCertPath(cmd *cobra.Command) string { - certPath, _ := cmd.Flags().GetString(tlsCertPathFlag) - return certPath -} - -func getKeyPath(cmd *cobra.Command) string { - keyPath, _ := cmd.Flags().GetString(tlsKeyPathFlag) - return keyPath -} - -func noTLS(cmd *cobra.Command) bool { - tls, _ := cmd.Flags().GetBool(noTLSFlag) - return tls -} diff --git a/pkg/cli/mockclients_test.go b/pkg/cli/mockclients_test.go deleted file mode 100644 index 187ceeb6f..000000000 --- a/pkg/cli/mockclients_test.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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. - -// Client Mocks -package cli - -import ( - "context" - "github.com/onosproject/onos-api/go/onos/config/admin" - "github.com/onosproject/onos-api/go/onos/config/diags" - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -// MockClientConfig is used by tests to set up which mock clients they want to use -type MockClientsConfig struct { - registeredModelsClient *MockConfigAdminServiceListRegisteredModelsClient - opstateClient *MockOpStateDiagsGetOpStateClient - listDeviceChangesClient *MockChangeServiceListDeviceChangesClient - listNetworkChangesClient *MockChangeServiceListNetworkChangesClient -} - -// mockConfigAdminServiceClient is the mock for the ConfigAdminServiceClient -type mockConfigAdminServiceClient struct { - rollBackID string - registeredModelsClient *MockConfigAdminServiceListRegisteredModelsClient -} - -var LastCreatedClient *mockConfigAdminServiceClient - -func (c mockConfigAdminServiceClient) UploadRegisterModel(ctx context.Context, opts ...grpc.CallOption) (admin.ConfigAdminService_UploadRegisterModelClient, error) { - // TODO Implement this - return nil, nil -} - -func (c mockConfigAdminServiceClient) ListRegisteredModels(ctx context.Context, in *admin.ListModelsRequest, opts ...grpc.CallOption) (admin.ConfigAdminService_ListRegisteredModelsClient, error) { - return c.registeredModelsClient, nil -} - -func (c mockConfigAdminServiceClient) RollbackNetworkChange(ctx context.Context, in *admin.RollbackRequest, opts ...grpc.CallOption) (*admin.RollbackResponse, error) { - response := &admin.RollbackResponse{ - Message: "Rollback was successful", - } - LastCreatedClient.rollBackID = in.Name - return response, nil -} - -func (c mockConfigAdminServiceClient) RollbackNewNetworkChange(ctx context.Context, in *admin.RollbackRequest, opts ...grpc.CallOption) (*admin.RollbackResponse, error) { - response := &admin.RollbackResponse{ - Message: "Rollback was successful", - } - LastCreatedClient.rollBackID = in.Name - return response, nil -} - -func (c mockConfigAdminServiceClient) ListSnapshots(ctx context.Context, in *admin.ListSnapshotsRequest, opts ...grpc.CallOption) (admin.ConfigAdminService_ListSnapshotsClient, error) { - return nil, nil -} - -func (c mockConfigAdminServiceClient) CompactChanges(ctx context.Context, in *admin.CompactChangesRequest, opts ...grpc.CallOption) (*admin.CompactChangesResponse, error) { - return nil, nil -} - -// MockConfigAdminServiceListRegisteredModelsClient is a mock of the ConfigAdminServiceListRegisteredModelsClient -// Function pointers are used to allow mocking specific APIs -type MockConfigAdminServiceListRegisteredModelsClient struct { - recvFn func() (*admin.ModelInfo, error) - headerFn func() (metadata.MD, error) - trailerFn func() metadata.MD - closeSendFn func() error - contextFn func() context.Context - sendMsgFn func(interface{}) error - recvMsgFn func(interface{}) error -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) Recv() (*admin.ModelInfo, error) { - return c.recvFn() -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) Header() (metadata.MD, error) { - return c.headerFn() -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) Trailer() metadata.MD { - return c.trailerFn() -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) CloseSend() error { - return c.closeSendFn() -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) Context() context.Context { - return c.contextFn() -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) SendMsg(m interface{}) error { - return c.sendMsgFn(m) -} - -func (c MockConfigAdminServiceListRegisteredModelsClient) RecvMsg(m interface{}) error { - return c.recvMsgFn(m) -} - -// MockOpStateDiagsGetOpStateClient is a mock of the OpStateDiagsGetOpStateClient -// Function pointers are used to allow mocking specific APIs -type MockOpStateDiagsGetOpStateClient struct { - recvFn func() (*diags.OpStateResponse, error) - headerFn func() (metadata.MD, error) - trailerFn func() metadata.MD - closeSendFn func() error - contextFn func() context.Context - sendMsgFn func(interface{}) error - recvMsgFn func(interface{}) error -} - -func (c MockOpStateDiagsGetOpStateClient) Recv() (*diags.OpStateResponse, error) { - return c.recvFn() -} - -func (c MockOpStateDiagsGetOpStateClient) Header() (metadata.MD, error) { - return c.headerFn() -} - -func (c MockOpStateDiagsGetOpStateClient) Trailer() metadata.MD { - return c.trailerFn() -} - -func (c MockOpStateDiagsGetOpStateClient) CloseSend() error { - return c.closeSendFn() -} - -func (c MockOpStateDiagsGetOpStateClient) Context() context.Context { - return c.contextFn() -} - -func (c MockOpStateDiagsGetOpStateClient) SendMsg(m interface{}) error { - return c.sendMsgFn(m) -} - -func (c MockOpStateDiagsGetOpStateClient) RecvMsg(m interface{}) error { - return c.recvMsgFn(m) -} - -// mockOpStateDiagsClient is the mock for the OpStateDiagsClient -type mockOpStateDiagsClient struct { - getOpStateClient diags.OpStateDiags_GetOpStateClient -} - -func (m mockOpStateDiagsClient) GetOpState(ctx context.Context, in *diags.OpStateRequest, opts ...grpc.CallOption) (diags.OpStateDiags_GetOpStateClient, error) { - return m.getOpStateClient, nil -} - -// MockChangeServiceListDeviceChangesClient is a mock of the ChangeService_ListDeviceChangesClient -// Function pointers are used to allow mocking specific APIs -type MockChangeServiceListDeviceChangesClient struct { - recvFn func() (*diags.ListDeviceChangeResponse, error) - headerFn func() (metadata.MD, error) - trailerFn func() metadata.MD - closeSendFn func() error - contextFn func() context.Context - sendMsgFn func(interface{}) error - recvMsgFn func(interface{}) error -} - -func (c MockChangeServiceListDeviceChangesClient) Recv() (*diags.ListDeviceChangeResponse, error) { - return c.recvFn() -} - -func (c MockChangeServiceListDeviceChangesClient) Header() (metadata.MD, error) { - return c.headerFn() -} - -func (c MockChangeServiceListDeviceChangesClient) Trailer() metadata.MD { - return c.trailerFn() -} - -func (c MockChangeServiceListDeviceChangesClient) CloseSend() error { - return c.closeSendFn() -} - -func (c MockChangeServiceListDeviceChangesClient) Context() context.Context { - return c.contextFn() -} - -func (c MockChangeServiceListDeviceChangesClient) SendMsg(m interface{}) error { - return c.sendMsgFn(m) -} - -func (c MockChangeServiceListDeviceChangesClient) RecvMsg(m interface{}) error { - return c.recvMsgFn(m) -} - -// MockChangeServiceListNetworkChangesClient is a mock of the ChangeService_ListNetworkChangesClient -// Function pointers are used to allow mocking specific APIs -type MockChangeServiceListNetworkChangesClient struct { - recvFn func() (*diags.ListNetworkChangeResponse, error) - headerFn func() (metadata.MD, error) - trailerFn func() metadata.MD - closeSendFn func() error - contextFn func() context.Context - sendMsgFn func(interface{}) error - recvMsgFn func(interface{}) error - recvCounter func() int -} - -func (c MockChangeServiceListNetworkChangesClient) Recv() (*diags.ListNetworkChangeResponse, error) { - return c.recvFn() -} - -func (c MockChangeServiceListNetworkChangesClient) Header() (metadata.MD, error) { - return c.headerFn() -} - -func (c MockChangeServiceListNetworkChangesClient) Trailer() metadata.MD { - return c.trailerFn() -} - -func (c MockChangeServiceListNetworkChangesClient) CloseSend() error { - return c.closeSendFn() -} - -func (c MockChangeServiceListNetworkChangesClient) Context() context.Context { - return c.contextFn() -} - -func (c MockChangeServiceListNetworkChangesClient) SendMsg(m interface{}) error { - return c.sendMsgFn(m) -} - -func (c MockChangeServiceListNetworkChangesClient) RecvMsg(m interface{}) error { - return c.recvMsgFn(m) -} - -// mockChangeServiceClient is the mock for the ChangeServiceClient -type mockChangeServiceClient struct { - getChangeServiceClientDeviceChanges diags.ChangeService_ListDeviceChangesClient - getChangeServiceClientNetworkChanges diags.ChangeService_ListNetworkChangesClient -} - -func (m mockChangeServiceClient) ListNetworkChanges(ctx context.Context, in *diags.ListNetworkChangeRequest, opts ...grpc.CallOption) (diags.ChangeService_ListNetworkChangesClient, error) { - return m.getChangeServiceClientNetworkChanges, nil -} - -func (m mockChangeServiceClient) ListDeviceChanges(ctx context.Context, in *diags.ListDeviceChangeRequest, opts ...grpc.CallOption) (diags.ChangeService_ListDeviceChangesClient, error) { - return m.getChangeServiceClientDeviceChanges, nil -} - -// setUpMockClients sets up factories to create mocks of top level clients used by the CLI -func setUpMockClients(config MockClientsConfig) { - admin.ConfigAdminClientFactory = func(cc *grpc.ClientConn) admin.ConfigAdminServiceClient { - LastCreatedClient = &mockConfigAdminServiceClient{ - rollBackID: "", - registeredModelsClient: config.registeredModelsClient, - } - return LastCreatedClient - } - diags.OpStateDiagsClientFactory = func(cc *grpc.ClientConn) diags.OpStateDiagsClient { - return mockOpStateDiagsClient{ - getOpStateClient: config.opstateClient, - } - } - diags.ChangeServiceClientFactory = func(cc *grpc.ClientConn) diags.ChangeServiceClient { - return mockChangeServiceClient{ - getChangeServiceClientDeviceChanges: config.listDeviceChangesClient, - getChangeServiceClientNetworkChanges: config.listNetworkChangesClient, - } - } -} diff --git a/pkg/cli/models.go b/pkg/cli/models.go deleted file mode 100644 index ecc9ec398..000000000 --- a/pkg/cli/models.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "fmt" - "github.com/onosproject/onos-api/go/onos/config/admin" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" - "io" - "os" - "path/filepath" - "text/template" -) - -const modellistTemplate = "{{.Name}}: {{.Version}} from {{.Module}} containing:\n" + - "GetStateMode: {{.GetStateMode}}\n" + - "YANGS:\n" + - "{{range .ModelData}}" + - "\t{{.Name}}\t{{.Version}}\t{{.Organization}}\n" + - "{{end}}" + - "{{if .ReadOnlyPath}}" + - "Read Only Paths (subpaths not shown):\n" + - "{{range .ReadOnlyPath}}" + - "\t{{.Path}}\n" + - "{{end}}" + - "{{end}}" + - "{{if .ReadWritePath}}" + - "Read Write Paths (details not shown):\n" + - "{{range .ReadWritePath}}" + - "\t{{.Path}}\n" + - "{{end}}" + - "{{end}}" - -func getGetPluginsCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "plugins", - Short: "Lists the loaded model plugins", - Args: cobra.MaximumNArgs(1), - RunE: runListPluginsCommand, - } - cmd.Flags().BoolP("verbose", "v", false, "display verbose output") - return cmd -} - -func runListPluginsCommand(cmd *cobra.Command, args []string) error { - verbose, _ := cmd.Flags().GetBool("verbose") - tmplModelList, _ := template.New("change").Parse(modellistTemplate) - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := admin.CreateConfigAdminServiceClient(clientConnection) - - stream, err := client.ListRegisteredModels(context.Background(), &admin.ListModelsRequest{Verbose: verbose}) - if err != nil { - return fmt.Errorf("Failed to send request: %v", err) - } - - for { - in, err := stream.Recv() - if err == io.EOF { - return nil - } - if err != nil { - return err - } - _ = tmplModelList.Execute(cli.GetOutput(), in) - cli.Output("\n") - } -} - -func getAddPluginCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "plugin ", - Short: "Loads a new model plugin", - Args: cobra.ExactArgs(1), - RunE: runAddPluginCommand, - } - return cmd -} - -func runAddPluginCommand(cmd *cobra.Command, args []string) error { - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - - pluginFileName := "" - if len(args) == 1 { - pluginFileName = args[0] - } - pluginFile, err := os.Open(pluginFileName) - if err != nil { - return err - } - defer pluginFile.Close() - - client := admin.CreateConfigAdminServiceClient(clientConnection) - - uploadClient, err := client.UploadRegisterModel(context.Background()) - if err != nil { - return err - } - - const chunkSize = 2000000 - data := make([]byte, chunkSize) - var chunkNo int64 = 0 - for { - count, err := pluginFile.ReadAt(data, chunkNo*chunkSize) - if err == io.EOF { - err := uploadClient.Send(&admin.Chunk{ - SoFile: filepath.Base(pluginFileName), - Content: data[:count], - }) - if err != nil { - return err - } - resp, err := uploadClient.CloseAndRecv() - if err != nil { - return err - } - cli.Output("Plugin %s uploaded to server as %s:%s. %d chunks. %d bytes\n", - pluginFileName, resp.GetName(), resp.GetVersion(), - chunkNo, chunkNo*chunkSize+int64(count)) - return nil - } - if err != nil { - return err - } - err = uploadClient.Send(&admin.Chunk{ - SoFile: filepath.Base(pluginFileName), - Content: data, - }) - if err != nil { - return err - } - chunkNo++ - } -} diff --git a/pkg/cli/models_test.go b/pkg/cli/models_test.go deleted file mode 100644 index 5e3405c3e..000000000 --- a/pkg/cli/models_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "bytes" - "fmt" - "github.com/onosproject/onos-api/go/onos/config/admin" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/openconfig/gnmi/proto/gnmi" - "gotest.tools/assert" - "io" - "strings" - "testing" -) - -var modelInfo []admin.ModelInfo - -func generateModelData(count int) { - modelInfo = make([]admin.ModelInfo, count) - for modelIndex := range modelInfo { - roPaths := make([]*admin.ReadOnlyPath, 1) - roPaths[0] = &admin.ReadOnlyPath{ - Path: fmt.Sprintf("/root/ropath/path%d", modelIndex), - SubPath: nil, - } - modelData := make([]*gnmi.ModelData, 1) - modelData[0] = &gnmi.ModelData{ - Name: "UT NAME", - Organization: "UT ORG", - Version: "3.3.3", - } - modelInfo[modelIndex] = admin.ModelInfo{ - Name: fmt.Sprintf("Model-%d", modelIndex), - Version: "1.0", - Module: fmt.Sprintf("Module-%d", modelIndex), - GetStateMode: 1, - ReadOnlyPath: roPaths, - ModelData: modelData, - } - } -} - -var nextInfoIndex = 0 - -func recvMock() (*admin.ModelInfo, error) { - if nextInfoIndex < len(modelInfo) { - info := modelInfo[nextInfoIndex] - nextInfoIndex++ - - return &info, nil - } - return nil, io.EOF -} - -func Test_ListPlugins(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - generateModelData(4) - - modelsClient := MockConfigAdminServiceListRegisteredModelsClient{ - recvFn: recvMock, - } - - setUpMockClients(MockClientsConfig{registeredModelsClient: &modelsClient}) - plugins := getGetPluginsCommand() - args := make([]string, 1) - args[0] = "-v" - err := plugins.RunE(plugins, args) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Equal(t, strings.Count(output, "YANGS:"), len(modelInfo)) - assert.Equal(t, strings.Count(output, "GetStateMode: 1"), len(modelInfo)) - assert.Equal(t, strings.Count(output, "Model-"), len(modelInfo)) - assert.Equal(t, strings.Count(output, "Read Only Paths ("), len(modelInfo)) - assert.Assert(t, strings.Contains(output, "Model-1: 1.0 from Module-1")) - assert.Assert(t, strings.Contains(output, "UT NAME 3.3.3")) - assert.Assert(t, strings.Contains(output, "/root/ropath/path1")) -} - -func Test_AddPlugin(t *testing.T) { - // TODO remove this when the UploadRegisterModel is accessed - t.SkipNow() - const ( - pluginName = "MyNewPlugin.file" - pluginVersion = "1.0" - ) - - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - - setUpMockClients(MockClientsConfig{}) - addPlugin := getAddPluginCommand() - args := make([]string, 1) - - args[0] = pluginName - err := addPlugin.RunE(addPlugin, args) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Assert(t, strings.Contains(output, pluginName)) - assert.Assert(t, strings.Contains(output, pluginVersion)) -} diff --git a/pkg/cli/networkchanges.go b/pkg/cli/networkchanges.go deleted file mode 100644 index 6da34b833..000000000 --- a/pkg/cli/networkchanges.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - networkchange "github.com/onosproject/onos-api/go/onos/config/change/network" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" - "io" - "text/template" -) - -const changeHeader = "CHANGE INDEX REVISION PHASE STATE REASON MESSAGE\n" - -const changeHeaderFormat = "{{printf \"%-31v %-7d %-8d %-8s %-9s %-8s %s\" .ID .Index .Revision .Status.Phase .Status.State .Status.Reason .Status.Message}}\n" - -const typedValueFormat = "\t{{wrappath .Path 50 1| printf \"|%-50s|\"}}{{valuetostring .Value | printf \"(%s) %s\" .Value.Type | printf \"%-40s|\" }}{{printf \"%-7t|\" .Removed}}\n" - -const deviceIDFormat = "Device: {{.DeviceID}} ({{.DeviceVersion}})" - -const networkChangeTemplate = changeHeaderFormat + - "{{range .Changes}}\t" + deviceIDFormat + "\n{{end}}\n" - -const networkChangeTemplateVerbose = changeHeaderFormat + - "{{range .Changes}}\t" + deviceIDFormat + "\n" + - "{{range .Values}}" + typedValueFormat + "{{end}}\n" + - "{{end}}\n" - -func getWatchNetworkChangesCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "network-changes [changeId wildcard]", - Short: "Watch for network changes with updates", - Args: cobra.MaximumNArgs(1), - RunE: runWatchNetworkChangesCommand, - } - cmd.Flags().BoolP("verbose", "v", false, "whether to print the change with verbose output") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func getListNetworkChangesCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "network-changes [changeId wildcard]", - Short: "List current network changes", - Args: cobra.MaximumNArgs(1), - RunE: runListNetworkChangesCommand, - } - cmd.Flags().BoolP("verbose", "v", false, "whether to print the change with verbose output") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func runWatchNetworkChangesCommand(cmd *cobra.Command, args []string) error { - return networkChangesCommand(cmd, true, args) -} - -func runListNetworkChangesCommand(cmd *cobra.Command, args []string) error { - return networkChangesCommand(cmd, false, args) -} - -func networkChangesCommand(cmd *cobra.Command, subscribe bool, args []string) error { - var id networkchange.ID - if len(args) > 0 { - id = networkchange.ID(args[0]) - } - verbose, _ := cmd.Flags().GetBool("verbose") - noHeaders, _ := cmd.Flags().GetBool("no-headers") - - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := diags.CreateChangeServiceClient(clientConnection) - changesReq := diags.ListNetworkChangeRequest{ - Subscribe: subscribe, - ChangeID: id, - } - - var tmplChanges *template.Template - tmplChanges, _ = template.New("change").Funcs(funcMapChanges).Parse(networkChangeTemplate) - if verbose { - tmplChanges, _ = template.New("change").Funcs(funcMapChanges).Parse(networkChangeTemplateVerbose) - } - - stream, err := client.ListNetworkChanges(context.Background(), &changesReq) - if err != nil { - return err - } - - if !noHeaders { - cli.GetOutput().Write([]byte(changeHeader)) - } - for { - in, err := stream.Recv() - if err == io.EOF { - return nil - } - if err != nil { - return err - } - _ = tmplChanges.Execute(cli.GetOutput(), in.Change) - } -} diff --git a/pkg/cli/networkchanges_test.go b/pkg/cli/networkchanges_test.go deleted file mode 100644 index f5526cd9f..000000000 --- a/pkg/cli/networkchanges_test.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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. - -// Unit tests for watch and list network-changes CLI -package cli - -import ( - "bytes" - "fmt" - changetypes "github.com/onosproject/onos-api/go/onos/config/change" - devicechange "github.com/onosproject/onos-api/go/onos/config/change/device" - networkchange "github.com/onosproject/onos-api/go/onos/config/change/network" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "gotest.tools/assert" - "io" - "strings" - "testing" - "time" -) - -func generateNetworkChangeData(count int) { - networkChanges = make([]networkchange.NetworkChange, count) - now := time.Now() - - for cfgIdx := range networkChanges { - networkID := fmt.Sprintf("a_new_network_change-%d", cfgIdx) - - networkChanges[cfgIdx] = networkchange.NetworkChange{ - ID: networkchange.ID(networkID), - Index: networkchange.Index(cfgIdx), - Revision: 0, - Status: changetypes.Status{ - Phase: changetypes.Phase(cfgIdx % 2), - State: changetypes.State(cfgIdx % 4), - Reason: changetypes.Reason(cfgIdx % 2), - Message: "Test", - }, - Created: now, - Updated: now, - Changes: []*devicechange.Change{ - { - DeviceID: "device-1", - DeviceVersion: "1.0.0", - Values: []*devicechange.ChangeValue{ - { - Path: "/aa/bb/cc", - Value: devicechange.NewTypedValueString("Test1"), - Removed: false, - }, - { - Path: "/aa/bb/dd", - Value: devicechange.NewTypedValueString("Test2"), - Removed: false, - }, - }, - }, - { - DeviceID: "device-2", - DeviceVersion: "1.0.0", - Values: []*devicechange.ChangeValue{ - { - Path: "/aa/bb/cc", - Value: devicechange.NewTypedValueString("Test3"), - Removed: false, - }, - { - Path: "/aa/bb/dd", - Value: devicechange.NewTypedValueString("Test4"), - Removed: false, - }, - }, - }, - }, - Refs: []*networkchange.DeviceChangeRef{ - {DeviceChangeID: "device-1:1"}, - {DeviceChangeID: "device-2:1"}, - }, - Deleted: false, - } - } -} - -func Test_WatchNetworkChanges(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - generateDeviceChangeData(4) - generateNetworkChangeData(4) - - configsClient := MockChangeServiceListNetworkChangesClient{ - recvFn: recvWatchNetworkChangesMock, - } - - setUpMockClients(MockClientsConfig{ - listNetworkChangesClient: &configsClient, - }) - - networkChangesCmd := getWatchNetworkChangesCommand() - err := networkChangesCmd.RunE(networkChangesCmd, nil) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Equal(t, strings.Count(output, "a_new_network_change"), len(networkChanges)) -} - -var nextWatchNwChIndex int - -func recvWatchNetworkChangesMock() (*diags.ListNetworkChangeResponse, error) { - if nextWatchNwChIndex < len(networkChanges) { - netw := networkChanges[nextWatchNwChIndex] - nextWatchNwChIndex++ - - return &diags.ListNetworkChangeResponse{ - Change: &netw, - }, nil - } - return nil, io.EOF -} - -func Test_GetNetworkChanges(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - generateDeviceChangeData(4) - generateNetworkChangeData(4) - var nextNwChIndex = 0 - - configsClient := MockChangeServiceListNetworkChangesClient{ - recvFn: recvListNetworkChangesMock, - recvCounter: func() int { return nextNwChIndex }, - } - - setUpMockClients(MockClientsConfig{ - listNetworkChangesClient: &configsClient, - }) - - networkChangesCmd := getListNetworkChangesCommand() - err := networkChangesCmd.RunE(networkChangesCmd, nil) - assert.NilError(t, err) - output := outputBuffer.String() - assert.Equal(t, strings.Count(output, "a_new_network_change"), len(networkChanges)) - -} - -var nextListNwChIndex int - -func recvListNetworkChangesMock() (*diags.ListNetworkChangeResponse, error) { - if nextListNwChIndex < len(networkChanges) { - netw := networkChanges[nextListNwChIndex] - nextListNwChIndex++ - - return &diags.ListNetworkChangeResponse{ - Change: &netw, - }, nil - } - return nil, io.EOF -} diff --git a/pkg/cli/opstate.go b/pkg/cli/opstate.go deleted file mode 100644 index 8e26f12ef..000000000 --- a/pkg/cli/opstate.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "fmt" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" - "io" - "text/template" -) - -const opstateTemplate = "{{wrappath .Pathvalue.Path 80 0| printf \"%-80s|\"}}" + - "{{valuetostring .Pathvalue.Value | printf \"(%s) %s\" .Pathvalue.Value.Type | printf \"%-20s|\" }}" - -func getGetOpstateCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "opstate ", - Short: "Get the Opstate cache for a device", - Args: cobra.ExactArgs(1), - RunE: runGetOpstateCommand, - } - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func getWatchOpstateCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "opstate ", - Short: "Watch the Opstate cache for a device", - Args: cobra.ExactArgs(1), - RunE: runWatchOpstateCommand, - } - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func runGetOpstateCommand(cmd *cobra.Command, args []string) error { - return opstateCommand(cmd, false, args) -} - -func runWatchOpstateCommand(cmd *cobra.Command, args []string) error { - return opstateCommand(cmd, true, args) -} - -func opstateCommand(cmd *cobra.Command, subscribe bool, args []string) error { - deviceID := args[0] - noHeaders, _ := cmd.Flags().GetBool("no-headers") - tmplGetOpState, _ := template.New("change").Funcs(funcMapChanges).Parse(opstateTemplate) - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := diags.CreateOpStateDiagsClient(clientConnection) - - if !noHeaders { - cli.Output("OPSTATE CACHE: %s\n", deviceID) - cli.Output("%-82s|%-20s|\n", "PATH", "VALUE") - } - - stream, err := client.GetOpState(context.Background(), &diags.OpStateRequest{DeviceId: deviceID, Subscribe: subscribe}) - if err != nil { - return fmt.Errorf("failed to send request: %v", err) - } - - for { - in, err := stream.Recv() - if err == io.EOF { - // read done. - return nil - } - if err != nil { - return err - } - _ = tmplGetOpState.Execute(cli.GetOutput(), in) - cli.Output("\n") - } -} diff --git a/pkg/cli/opstate_test.go b/pkg/cli/opstate_test.go deleted file mode 100644 index 47732b081..000000000 --- a/pkg/cli/opstate_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "bytes" - "fmt" - devicechange "github.com/onosproject/onos-api/go/onos/config/change/device" - "github.com/onosproject/onos-api/go/onos/config/diags" - "github.com/onosproject/onos-lib-go/pkg/cli" - "gotest.tools/assert" - "io" - "regexp" - "strings" - "testing" -) - -var opstateInfo []diags.OpStateResponse - -func generateOpstate(count int) { - opstateInfo = make([]diags.OpStateResponse, count) - for opstateIndex := range opstateInfo { - valueString := fmt.Sprintf("value%d", opstateIndex) - pathString := fmt.Sprintf("/root/system/path%d", opstateIndex) - value := devicechange.PathValue{ - Path: pathString, - Value: devicechange.NewTypedValueString(valueString), - } - opstateInfo[opstateIndex] = diags.OpStateResponse{ - Type: 0, - Pathvalue: &value, - } - } -} - -var nextOpstateIndex = 0 - -func recvOpstateMock() (*diags.OpStateResponse, error) { - if nextOpstateIndex < len(opstateInfo) { - opstate := opstateInfo[nextOpstateIndex] - nextOpstateIndex++ - - return &opstate, nil - } - return nil, io.EOF -} - -func Test_Opstate(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - - opStateClient := MockOpStateDiagsGetOpStateClient{ - recvFn: recvOpstateMock, - } - - setUpMockClients(MockClientsConfig{opstateClient: &opStateClient}) - generateOpstate(3) - opstateCmd := getGetOpstateCommand() - args := make([]string, 1) - args[0] = "My Device" - err := opstateCmd.RunE(opstateCmd, args) - assert.NilError(t, err, "Error fetching opstate command") - outputString := outputBuffer.String() - output := strings.Split(strings.TrimSuffix(outputString, "\n"), "\n") - - testCases := []struct { - description string - index int - regexp string - }{ - {description: "Path 0", index: 2, regexp: `/root/system/path0\s+\|\(STRING\) value0 +\|`}, - {description: "Path 1", index: 3, regexp: `/root/system/path1\s+\|\(STRING\) value1 +\|`}, - {description: "Path 2", index: 4, regexp: `/root/system/path2\s+\|\(STRING\) value2 +\|`}, - {description: "Header", index: 0, regexp: `OPSTATE CACHE: My Device`}, - {description: "Column Headers", index: 1, regexp: `PATH +\|VALUE`}, - } - - for _, testCase := range testCases { - re := regexp.MustCompile(testCase.regexp) - assert.Assert(t, re.MatchString(output[testCase.index]), - testCase.description, fmt.Sprintf(". '%s' does not match '%s'", re.String(), output[testCase.index])) - } -} diff --git a/pkg/cli/rollback.go b/pkg/cli/rollback.go deleted file mode 100644 index e35fc3f5e..000000000 --- a/pkg/cli/rollback.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "github.com/onosproject/onos-api/go/onos/config/admin" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" -) - -func getRollbackCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "rollback ", - Short: "Rolls-back a network change", - Args: cobra.MaximumNArgs(1), - RunE: runRollbackCommand, - } - return cmd -} - -func runRollbackCommand(cmd *cobra.Command, args []string) error { - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := admin.CreateConfigAdminServiceClient(clientConnection) - - changeID := "" - if len(args) == 1 { - changeID = args[0] - } - - resp, err := client.RollbackNetworkChange( - context.Background(), &admin.RollbackRequest{Name: changeID}) - if err != nil { - return err - } - cli.Output("Rollback success %s\n", resp.Message) - return nil -} diff --git a/pkg/cli/rollback_test.go b/pkg/cli/rollback_test.go deleted file mode 100644 index d5404567c..000000000 --- a/pkg/cli/rollback_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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. - -// Unit tests for rollback CLI -package cli - -import ( - "bytes" - "github.com/onosproject/onos-lib-go/pkg/cli" - "gotest.tools/assert" - "strings" - "testing" -) - -func Test_rollback(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - cli.CaptureOutput(outputBuffer) - - setUpMockClients(MockClientsConfig{}) - rollback := getRollbackCommand() - args := make([]string, 1) - args[0] = "ABCD1234" - err := rollback.RunE(rollback, args) - assert.NilError(t, err) - assert.Equal(t, LastCreatedClient.rollBackID, "ABCD1234") - output := outputBuffer.String() - assert.Assert(t, strings.Contains(output, "Rollback was successful")) -} diff --git a/pkg/cli/root.go b/pkg/cli/root.go deleted file mode 100644 index 84573b65d..000000000 --- a/pkg/cli/root.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 holds ONOS command-line command implementations. -package cli - -import ( - clilib "github.com/onosproject/onos-lib-go/pkg/cli" - loglib "github.com/onosproject/onos-lib-go/pkg/logging/cli" - "github.com/spf13/cobra" -) - -const ( - configName = "config" - defaultAddress = "onos-config:5150" -) - -// init initializes the command line -func init() { - clilib.InitConfig(configName) -} - -// Init is a hook called after cobra initialization -func Init() { - // noop for now -} - -// GetCommand returns the root command for the config service. -func GetCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "config {get,add,rollback,snapshot,compact-changes,watch,load} [args]", - Short: "ONOS configuration subsystem commands", - } - - clilib.AddConfigFlags(cmd, defaultAddress) - - cmd.AddCommand(clilib.GetConfigCommand()) - cmd.AddCommand(getGetCommand()) - cmd.AddCommand(getAddCommand()) - cmd.AddCommand(getRollbackCommand()) - cmd.AddCommand(getCompactCommand()) - cmd.AddCommand(getWatchCommand()) - cmd.AddCommand(getLoadCommand()) - cmd.AddCommand(loglib.GetCommand()) - return cmd -} diff --git a/pkg/cli/root_test.go b/pkg/cli/root_test.go deleted file mode 100644 index b0e40874b..000000000 --- a/pkg/cli/root_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "bytes" - "strings" - "testing" - - "gotest.tools/assert" -) - -// Test_RootUsage tests the creation of the root command and checks that the ONOS usage messages are included -func Test_RootUsage(t *testing.T) { - outputBuffer := bytes.NewBufferString("") - - testCases := []struct { - description string - expected string - }{ - {description: "Roll back command", expected: `Rolls-back a network change`}, - {description: "Usage header", expected: `Usage:`}, - {description: "Usage config command", expected: `config [command]`}, - } - - cmd := GetCommand() - assert.Assert(t, cmd != nil) - cmd.SetOut(outputBuffer) - - usageErr := cmd.Usage() - assert.NilError(t, usageErr) - - output := outputBuffer.String() - - for _, testCase := range testCases { - assert.Assert(t, strings.Contains(output, testCase.expected), `Expected output "%s"" for %s not found`, - testCase.expected, testCase.description) - } -} - -// Test_SubCommands tests that the ONOS supplied sub commands are present in the root -func Test_SubCommands(t *testing.T) { - cmds := GetCommand().Commands() - assert.Assert(t, cmds != nil) - - testCases := []struct { - commandName string - expectedShort string - }{ - {commandName: "Config", expectedShort: "Manage the CLI configuration"}, - {commandName: "Rollback", expectedShort: "Rolls-back a network change"}, - {commandName: "Add", expectedShort: "Add a config resource"}, - {commandName: "Get", expectedShort: "Get config resources"}, - {commandName: "Compact-Changes", expectedShort: "Takes a snapshot of network and device changes"}, - {commandName: "Watch", expectedShort: "Watch for updates to a config resource type"}, - {commandName: "Log", expectedShort: "logging api commands"}, - {commandName: "Load", expectedShort: "Load configuration from a file"}, - } - - var subCommandsFound = make(map[string]bool) - for _, cmd := range cmds { - subCommandsFound[cmd.Short] = false - } - - // Each sub command should be found once and only once - assert.Equal(t, len(subCommandsFound), len(testCases)) - for _, testCase := range testCases { - // check that this is an expected sub command - entry, entryFound := subCommandsFound[testCase.expectedShort] - assert.Assert(t, entryFound, "Subcommand %s not found", testCase.commandName) - assert.Assert(t, entry == false, "command %s found more than once", testCase.commandName) - subCommandsFound[testCase.expectedShort] = true - } - - // Each sub command should have been found - for _, testCase := range testCases { - // check that this is an expected sub command - entry, entryFound := subCommandsFound[testCase.expectedShort] - assert.Assert(t, entryFound) - assert.Assert(t, entry, "command %s was not found", testCase.commandName) - } -} diff --git a/pkg/cli/snapshot.go b/pkg/cli/snapshot.go deleted file mode 100644 index ef0d1e604..000000000 --- a/pkg/cli/snapshot.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019-present Open Networking Foundation. -// -// 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 ( - "context" - "github.com/onosproject/onos-api/go/onos/config/admin" - device_snapshot "github.com/onosproject/onos-api/go/onos/config/snapshot/device" - "github.com/onosproject/onos-lib-go/pkg/cli" - "github.com/spf13/cobra" - "io" - "text/template" -) - -const snapshotHeader = "ID DEVICE VERSION TYPE INDEX SNAPSHOTID\n" - -const snapshotsHeaderFormat = "{{printf \"%-24s %-16s %-8s %-12s %-6d %s\" .ID .DeviceID .DeviceVersion .DeviceType .ChangeIndex .SnapshotID}}\n" - -const pathValueTemplate = "{{wrappath .Path 80 0| printf \"%-80s|\"}}" + - "{{valuetostring .Value | printf \"(%s) %s\" .Value.Type | printf \"%-40s|\" }}" - -const snapshotsTemplate = snapshotsHeaderFormat - -const snapshotsTemplateVerbose = snapshotsHeaderFormat + - "{{range .Values}}" + pathValueTemplate + "\n{{end}}\n" - -func getWatchSnapshotsCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "snapshots [id wildcard]", - Short: "Watch for snapshots with updates", - Args: cobra.MaximumNArgs(1), - RunE: runWatchSnapshotsCommand, - } - cmd.Flags().BoolP("verbose", "v", false, "whether to print the change with verbose output") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func getListSnapshotsCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "snapshots [id wildcard]", - Short: "List snapshots", - Args: cobra.MaximumNArgs(1), - RunE: runListSnapshotsCommand, - } - cmd.Flags().BoolP("verbose", "v", false, "whether to print the change with verbose output") - cmd.Flags().Bool("no-headers", false, "disables output headers") - return cmd -} - -func runWatchSnapshotsCommand(cmd *cobra.Command, args []string) error { - return snapshotsCommand(cmd, true, args) -} - -func runListSnapshotsCommand(cmd *cobra.Command, args []string) error { - return snapshotsCommand(cmd, false, args) -} - -func snapshotsCommand(cmd *cobra.Command, subscribe bool, args []string) error { - var id device_snapshot.ID - if len(args) > 0 { - id = device_snapshot.ID(args[0]) - } - verbose, _ := cmd.Flags().GetBool("verbose") - noHeaders, _ := cmd.Flags().GetBool("no-headers") - - clientConnection, clientConnectionError := cli.GetConnection(cmd) - - if clientConnectionError != nil { - return clientConnectionError - } - client := admin.CreateConfigAdminServiceClient(clientConnection) - snapshotsRequest := admin.ListSnapshotsRequest{ - Subscribe: subscribe, - ID: id, - } - - var tmplSnapshots *template.Template - tmplSnapshots, _ = template.New("snapshots").Funcs(funcMapChanges).Parse(snapshotsTemplate) - if verbose { - tmplSnapshots, _ = template.New("snapshots").Funcs(funcMapChanges).Parse(snapshotsTemplateVerbose) - } - - stream, err := client.ListSnapshots(context.Background(), &snapshotsRequest) - if err != nil { - return err - } - - if !noHeaders { - cli.GetOutput().Write([]byte(snapshotHeader)) - } - for { - in, err := stream.Recv() - if err == io.EOF { - return nil - } - if err != nil { - return err - } - err = tmplSnapshots.Execute(cli.GetOutput(), in) - if err != nil { - cli.Output("ERROR on template: %s", snapshotsTemplate) - return err - } - } -}