diff --git a/cli/http.go b/cli/http.go index 746c4a45146a882d827ef4b58526a5e06e4ef9a3..a90be457ba4e72d9c1a9005fb81c6b9860410039 100644 --- a/cli/http.go +++ b/cli/http.go @@ -58,6 +58,8 @@ func HTTPGet(apiEndpoint, f string, args ...string) error { uuid := string(bytes[19:55]) viper.Set("LAST_DEVICE_UUID", uuid) fmt.Println(string(bytes)) + case http.StatusAccepted: + default: log.WithFields(log.Fields{ "status code": resp.StatusCode, diff --git a/cli/set.go b/cli/set.go index 4d01d1477fd281446c3666faaf69e9a9899f7347..c5499d6f3a085db76d03fcef3227645662e829fc 100644 --- a/cli/set.go +++ b/cli/set.go @@ -3,10 +3,7 @@ package cli import ( "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" "code.fbi.h-da.de/cocsn/gosdn/nucleus" - "code.fbi.h-da.de/cocsn/gosdn/nucleus/util/proto" "context" - pb "google.golang.org/protobuf/proto" - "os" ) // Set sends a gNMI Set request to the specified target. Only one @@ -23,28 +20,5 @@ func Set(a, u, p, typ string, args ...string) error { if err != nil { return err } - - path := gnmi.SplitPath(args[0]) - req := []interface{}{ - &gnmi.Operation{ - Type: typ, - Origin: "", - Target: "", - Path: path, - Val: args[1], - }, - } - - resp, err := t.Set(context.Background(), req...) - if err != nil { - return err - } - - _, tap := os.LookupEnv("GOSDN_TAP") - if tap { - if err := proto.Write(resp.(pb.Message), "resp-set-system-config-hostname"); err != nil { - return err - } - } - return nil + return t.Set(context.Background(), args) } diff --git a/cmd/change.go b/cmd/change.go new file mode 100644 index 0000000000000000000000000000000000000000..fc10bdb4fb746317c2450b4548cfae680115769f --- /dev/null +++ b/cmd/change.go @@ -0,0 +1,49 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "github.com/spf13/cobra" +) + +// changeCmd represents the change command +var changeCmd = &cobra.Command{ + Use: "change", + Short: "manage changes of the specified pnd", + Long: `use "change list" or "change list-pending" to list changes + +use "change commit" or "change confirm" respectively`, +} + +func init() { + cliCmd.AddCommand(changeCmd) +} diff --git a/cmd/cliSet.go b/cmd/cliSet.go index 9a79c630bed30d80c0d8438224edc42f084ff14d..e3f3a0743fdea2fa9c5c2ebd5686ef2e6675dc6b 100644 --- a/cmd/cliSet.go +++ b/cmd/cliSet.go @@ -41,12 +41,14 @@ var cliSetCmd = &cobra.Command{ Use: "set", Args: cobra.ExactArgs(2), Short: "set a value on a device", - Long: `Set a path value for a given device. Only one path and -only one value supported for now`, + Long: `Update a path value for a given device. Only one path and +only one value supported for now. + +Use "set replace" or "set delete" respectively`, RunE: func(cmd *cobra.Command, args []string) error { return cli.HTTPGet( apiEndpoint, - "set", + "update", "uuid="+uuid, "cliSbi="+cliSbi, "cliPnd="+cliPnd, @@ -60,5 +62,5 @@ only one value supported for now`, func init() { cliCmd.AddCommand(cliSetCmd) - cliSetCmd.Flags().StringVar(&uuid, "uuid", "", "uuid of the requested device") + cliSetCmd.PersistentFlags().StringVar(&uuid, "uuid", "", "uuid of the target device") } diff --git a/cmd/commit.go b/cmd/commit.go new file mode 100644 index 0000000000000000000000000000000000000000..3e3937c3dd8ed918ce4cbe57719a0ef4deeff8e6 --- /dev/null +++ b/cmd/commit.go @@ -0,0 +1,57 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// commitCmd represents the commit command +var commitCmd = &cobra.Command{ + Use: "commit", + Args: cobra.ExactArgs(1), + Short: "Commit the given change for the active PND", + Long: ``, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "change-commit", + "pnd="+cliPnd, + "cuid="+args[0], + ) + }, +} + +func init() { + changeCmd.AddCommand(commitCmd) +} diff --git a/cmd/confirm.go b/cmd/confirm.go new file mode 100644 index 0000000000000000000000000000000000000000..4707a8e5e7460802a54e5ec9f8ae121591206a61 --- /dev/null +++ b/cmd/confirm.go @@ -0,0 +1,57 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// confirmCmd represents the confirm command +var confirmCmd = &cobra.Command{ + Use: "confirm", + Args: cobra.ExactArgs(1), + Short: "Confirms the given change for the active PND", + Long: ``, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "change-confirm", + "pnd="+cliPnd, + "cuid="+args[0], + ) + }, +} + +func init() { + changeCmd.AddCommand(confirmCmd) +} diff --git a/cmd/delete.go b/cmd/delete.go new file mode 100644 index 0000000000000000000000000000000000000000..3c4e4e7603c32be00c4bba428bd22b09cd735eea --- /dev/null +++ b/cmd/delete.go @@ -0,0 +1,71 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// deleteCmd represents the delete command +var deleteCmd = &cobra.Command{ + Use: "delete", + Args: cobra.ExactArgs(1), + Short: "set a value on a device", + Long: `Set a path value for a given device. Only one path and +only one value supported for now`, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "delete", + "uuid="+uuid, + "cliSbi="+cliSbi, + "cliPnd="+cliPnd, + "path="+args[0], + "address="+address, + ) + }, +} + +func init() { + cliSetCmd.AddCommand(deleteCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/list.go b/cmd/list.go new file mode 100644 index 0000000000000000000000000000000000000000..2e3a0ce52e18d3b457de393cda1869addc3715d5 --- /dev/null +++ b/cmd/list.go @@ -0,0 +1,55 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// listCmd represents the list command +var listCmd = &cobra.Command{ + Use: "list", + Short: "Lists all committed changes", + Long: ``, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "change-list", + "pnd="+cliPnd, + ) + }, +} + +func init() { + changeCmd.AddCommand(listCmd) +} diff --git a/cmd/listPending.go b/cmd/listPending.go new file mode 100644 index 0000000000000000000000000000000000000000..4d5ece8fee0055c1b2d4439ace77680927789a4f --- /dev/null +++ b/cmd/listPending.go @@ -0,0 +1,55 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// listPendingCmd represents the listPending command +var listPendingCmd = &cobra.Command{ + Use: "listPending", + Short: "Lists all committed changes", + Long: ``, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "change-list-pending", + "pnd="+cliPnd, + ) + }, +} + +func init() { + changeCmd.AddCommand(listPendingCmd) +} diff --git a/cmd/replace.go b/cmd/replace.go new file mode 100644 index 0000000000000000000000000000000000000000..33529c6d0e647aa9494b0dec9eee4ea2b2253818 --- /dev/null +++ b/cmd/replace.go @@ -0,0 +1,62 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// replaceCmd represents the replace command +var replaceCmd = &cobra.Command{ + Use: "replace", + Args: cobra.ExactArgs(2), + Short: "set a value on a device", + Long: `Set a path value for a given device. Only one path and +only one value supported for now`, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "replace", + "uuid="+uuid, + "cliSbi="+cliSbi, + "cliPnd="+cliPnd, + "path="+args[0], + "address="+address, + "value="+args[1], + ) + }, +} + +func init() { + cliSetCmd.AddCommand(replaceCmd) +} diff --git a/cmd/update.go b/cmd/update.go new file mode 100644 index 0000000000000000000000000000000000000000..93db8e374adf4553675bd14db98c29b09ee88052 --- /dev/null +++ b/cmd/update.go @@ -0,0 +1,62 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/cocsn/gosdn/cli" + "github.com/spf13/cobra" +) + +// updateCmd represents the update command +var updateCmd = &cobra.Command{ + Use: "update", + Args: cobra.ExactArgs(2), + Short: "update a value on a device", + Long: `Update a path value for a given device. Only one path and +only one value supported for now`, + RunE: func(cmd *cobra.Command, args []string) error { + return cli.HTTPGet( + apiEndpoint, + "update", + "uuid="+uuid, + "cliSbi="+cliSbi, + "cliPnd="+cliPnd, + "path="+args[0], + "address="+address, + "value="+args[1], + ) + }, +} + +func init() { + cliSetCmd.AddCommand(updateCmd) +} diff --git a/go.mod b/go.mod index e34ad1f7839c9f774d5f1319c3ad05b654dc876c..c3595c3e3c9bf7cfe659b8fa65dff53fcf79a714 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/neo4j/neo4j-go-driver v1.8.3 github.com/openconfig/gnmi v0.0.0-20200617225440-d2b4e6a45802 github.com/openconfig/goyang v0.2.3 - github.com/openconfig/ygot v0.10.0 + github.com/openconfig/ygot v0.10.4 github.com/sirupsen/logrus v1.8.0 github.com/spf13/cobra v1.1.1 github.com/spf13/viper v1.7.1 diff --git a/go.sum b/go.sum index ccec3caa45e621417689f472330ef8a6c83794fd..dfc84d46a711f66bbcaac6e485f4bdbc96f34d2b 100644 --- a/go.sum +++ b/go.sum @@ -441,6 +441,8 @@ github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQS github.com/openconfig/ygot v0.9.0/go.mod h1:oCQNdXnv7dWc8scTDgoFkauv1wwplJn5HspHcjlxSAQ= github.com/openconfig/ygot v0.10.0 h1:EmgwLXbFiCBmEUlSI4/1fPuRzgf4EsD0sThmAmRqbYM= github.com/openconfig/ygot v0.10.0/go.mod h1:oCQNdXnv7dWc8scTDgoFkauv1wwplJn5HspHcjlxSAQ= +github.com/openconfig/ygot v0.10.4 h1:7rfvHEWFBYxFeVVK9UbMq6BJMAD7zeedidEUuxhcfaU= +github.com/openconfig/ygot v0.10.4/go.mod h1:oCQNdXnv7dWc8scTDgoFkauv1wwplJn5HspHcjlxSAQ= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= diff --git a/mocks/PrincipalNetworkDomain.go b/mocks/PrincipalNetworkDomain.go index 38233e76794d9913cf722aa848b2409fe4e1e499..3645a6215e5e79a44adbae955facaa66fcb639f4 100644 --- a/mocks/PrincipalNetworkDomain.go +++ b/mocks/PrincipalNetworkDomain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery 2.7.4. DO NOT EDIT. package mocks @@ -6,6 +6,8 @@ import ( mock "github.com/stretchr/testify/mock" uuid "github.com/google/uuid" + + ygot "github.com/openconfig/ygot/ygot" ) // PrincipalNetworkDomain is an autogenerated mock type for the PrincipalNetworkDomain type @@ -41,6 +43,50 @@ func (_m *PrincipalNetworkDomain) AddSbi(_a0 interface{}) error { return r0 } +// ChangeOND provides a mock function with given fields: _a0, operation, path, value +func (_m *PrincipalNetworkDomain) ChangeOND(_a0 uuid.UUID, operation interface{}, path string, value ...string) error { + _va := make([]interface{}, len(value)) + for _i := range value { + _va[_i] = value[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, operation, path) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(uuid.UUID, interface{}, string, ...string) error); ok { + r0 = rf(_a0, operation, path, value...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Committed provides a mock function with given fields: _a0 +func (_m *PrincipalNetworkDomain) Committed(_a0 uuid.UUID) (interface{}, error) { + ret := _m.Called(_a0) + + var r0 interface{} + if rf, ok := ret.Get(0).(func(uuid.UUID) interface{}); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(uuid.UUID) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ContainsDevice provides a mock function with given fields: _a0 func (_m *PrincipalNetworkDomain) ContainsDevice(_a0 uuid.UUID) bool { ret := _m.Called(_a0) @@ -83,6 +129,29 @@ func (_m *PrincipalNetworkDomain) GetDescription() string { return r0 } +// GetDevice provides a mock function with given fields: _a0 +func (_m *PrincipalNetworkDomain) GetDevice(_a0 uuid.UUID) (ygot.GoStruct, error) { + ret := _m.Called(_a0) + + var r0 ygot.GoStruct + if rf, ok := ret.Get(0).(func(uuid.UUID) ygot.GoStruct); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ygot.GoStruct) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(uuid.UUID) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetName provides a mock function with given fields: func (_m *PrincipalNetworkDomain) GetName() string { ret := _m.Called() @@ -113,7 +182,7 @@ func (_m *PrincipalNetworkDomain) GetSBIs() interface{} { return r0 } -// Id provides a mock function with given fields: +// ID provides a mock function with given fields: func (_m *PrincipalNetworkDomain) ID() uuid.UUID { ret := _m.Called() @@ -129,6 +198,38 @@ func (_m *PrincipalNetworkDomain) ID() uuid.UUID { return r0 } +// ListCommitted provides a mock function with given fields: +func (_m *PrincipalNetworkDomain) ListCommitted() []uuid.UUID { + ret := _m.Called() + + var r0 []uuid.UUID + if rf, ok := ret.Get(0).(func() []uuid.UUID); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]uuid.UUID) + } + } + + return r0 +} + +// ListPending provides a mock function with given fields: +func (_m *PrincipalNetworkDomain) ListPending() []uuid.UUID { + ret := _m.Called() + + var r0 []uuid.UUID + if rf, ok := ret.Get(0).(func() []uuid.UUID); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]uuid.UUID) + } + } + + return r0 +} + // MarshalDevice provides a mock function with given fields: _a0 func (_m *PrincipalNetworkDomain) MarshalDevice(_a0 uuid.UUID) (string, error) { ret := _m.Called(_a0) @@ -150,6 +251,29 @@ func (_m *PrincipalNetworkDomain) MarshalDevice(_a0 uuid.UUID) (string, error) { return r0, r1 } +// Pending provides a mock function with given fields: _a0 +func (_m *PrincipalNetworkDomain) Pending(_a0 uuid.UUID) (interface{}, error) { + ret := _m.Called(_a0) + + var r0 interface{} + if rf, ok := ret.Get(0).(func(uuid.UUID) interface{}); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(uuid.UUID) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RemoveDevice provides a mock function with given fields: _a0 func (_m *PrincipalNetworkDomain) RemoveDevice(_a0 uuid.UUID) error { ret := _m.Called(_a0) diff --git a/mocks/SouthboundInterface.go b/mocks/SouthboundInterface.go index 6217f5a7674db004f64254bfe5d5c8348ac733a7..38ffb81ff021989bb8153c33169ce40ad8863a33 100644 --- a/mocks/SouthboundInterface.go +++ b/mocks/SouthboundInterface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery 2.7.4. DO NOT EDIT. package mocks @@ -18,7 +18,7 @@ type SouthboundInterface struct { mock.Mock } -// Id provides a mock function with given fields: +// ID provides a mock function with given fields: func (_m *SouthboundInterface) ID() uuid.UUID { ret := _m.Called() diff --git a/mocks/Storable.go b/mocks/Storable.go index 630f70145d05ec4878461e243d238fe59958a483..e55a23eb41a51d2715f2ee94dfbb9e7a285a0145 100644 --- a/mocks/Storable.go +++ b/mocks/Storable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery 2.7.4. DO NOT EDIT. package mocks @@ -13,7 +13,7 @@ type Storable struct { mock.Mock } -// Id provides a mock function with given fields: +// ID provides a mock function with given fields: func (_m *Storable) ID() uuid.UUID { ret := _m.Called() diff --git a/mocks/Transport.go b/mocks/Transport.go index 6dc256acae1ee730623be6ab1fd5508f9f4ed9f5..7d8531e57334fd330a698165132428273d618f39 100644 --- a/mocks/Transport.go +++ b/mocks/Transport.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery 2.7.4. DO NOT EDIT. package mocks @@ -76,29 +76,20 @@ func (_m *Transport) ProcessResponse(resp interface{}, root interface{}, models } // Set provides a mock function with given fields: ctx, params -func (_m *Transport) Set(ctx context.Context, params ...interface{}) (interface{}, error) { +func (_m *Transport) Set(ctx context.Context, params ...interface{}) error { var _ca []interface{} _ca = append(_ca, ctx) _ca = append(_ca, params...) ret := _m.Called(_ca...) - var r0 interface{} - if rf, ok := ret.Get(0).(func(context.Context, ...interface{}) interface{}); ok { + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, ...interface{}) error); ok { r0 = rf(ctx, params...) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(interface{}) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, ...interface{}) error); ok { - r1 = rf(ctx, params...) - } else { - r1 = ret.Error(1) + r0 = ret.Error(0) } - return r0, r1 + return r0 } // Subscribe provides a mock function with given fields: ctx, params diff --git a/mocks/TransportOptions.go b/mocks/TransportOptions.go index 4893655f8a5bc0fef06e4898e116fc3df7171421..b969fdb60e490658017a191dfb2bae818408b83a 100644 --- a/mocks/TransportOptions.go +++ b/mocks/TransportOptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery 2.7.4. DO NOT EDIT. package mocks diff --git a/nucleus/gnmi_transport.go b/nucleus/gnmi_transport.go index 3566855d7c2f81195e8adeb0b01ef12e3df140bc..80441b0c6322b55d53569e1b15c3f35c28a7a9ba 100644 --- a/nucleus/gnmi_transport.go +++ b/nucleus/gnmi_transport.go @@ -2,8 +2,7 @@ package nucleus import ( "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" - "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" - pathutils"code.fbi.h-da.de/cocsn/gosdn/nucleus/util/path" + pathutils "code.fbi.h-da.de/cocsn/gosdn/nucleus/util/path" "context" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/gnmi/proto/gnmi_ext" @@ -242,10 +241,6 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch return nil } -func (g *Gnmi) TranslateChange(i ...interface{}) (*pnd.Change, error) { - panic("implement me") -} - // Capabilities calls GNMI capabilities func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { log.WithFields(log.Fields{ diff --git a/nucleus/gnmi_transport_test.go b/nucleus/gnmi_transport_test.go index 38270c8da5fe3f31f030c5010de2b980a8d8d127..18627bd9349ab7d740a80bd5472c7eda045632bf 100644 --- a/nucleus/gnmi_transport_test.go +++ b/nucleus/gnmi_transport_test.go @@ -276,7 +276,6 @@ func TestGnmi_Set(t *testing.T) { name string fields fields args args - want interface{} wantErr bool }{ { @@ -285,20 +284,15 @@ func TestGnmi_Set(t *testing.T) { args: args{ params: nil, }, - want: nil, wantErr: true, }, // TODO: Positive test cases } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.fields.transport.Set(context.Background(), tt.args.params...) + err := tt.fields.transport.Set(context.Background(), tt.args.params...) if (err != nil) != tt.wantErr { t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Set() got = %v, want %v", got, tt.want) } }) } diff --git a/nucleus/http.go b/nucleus/http.go index 56ad4cb0af707662e72656e1a7b6a4fa0a88f046..621d0d30ca7071a675f67d7b8ee62a4bf1340dd9 100644 --- a/nucleus/http.go +++ b/nucleus/http.go @@ -2,16 +2,24 @@ package nucleus import ( "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" + . "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" "context" "fmt" "github.com/google/uuid" gpb "github.com/openconfig/gnmi/proto/gnmi" log "github.com/sirupsen/logrus" + "io" "net/http" "net/url" "time" ) +var apiOpmap = map[string]Operation{ + "update": TRANSPORT_UPDATE, + "replace": TRANSPORT_REPLACE, + "delete": TRANSPORT_DELETE, +} + func stopHttpServer() error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -61,7 +69,6 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { return } - id, err := uuid.Parse(query.Get("uuid")) if err != nil { if err.Error() != "invalid UUID length: 0" { @@ -88,23 +95,18 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { if query.Get("q") != "init" && query.Get("q") != "getIDs" { pnd, err = c.pndc.get(pid) if err != nil { - log.Error(err) - writer.WriteHeader(http.StatusInternalServerError) + handleServerError(writer, err) return } sbic := pnd.GetSBIs() sbi, err = sbic.(*sbiStore).get(sid) if err != nil { - log.WithFields(log.Fields{ - "requested uuid": sid, - "available uuids": sbic.(*sbiStore).UUIDs(), - }).Error(err) - writer.WriteHeader(http.StatusInternalServerError) + handleServerError(writer, err) return } } - switch query.Get("q") { + switch q := query.Get("q"); q { case "addDevice": d, err := NewDevice(sbi, &GnmiTransportOptions{ Config: gnmi.Config{ @@ -167,42 +169,81 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Content-Type", "application/json") fmt.Fprintf(writer, "%v", device) case "getIDs": - writeIDs := func(typ string, ids []uuid.UUID) { - fmt.Fprintf(writer, "%v:\n", typ) - for i, id := range ids { - fmt.Fprintf(writer, "%v: %v\n", i+1, id) - } - } + pnds := c.pndc.UUIDs() - writeIDs("PNDs", pnds) - writeIDs("SBIs", c.sbic.UUIDs()) - for _,id := range pnds{ + writeIDs(writer, "PNDs", pnds) + writeIDs(writer, "SBIs", c.sbic.UUIDs()) + for _, id := range pnds { p, err := c.pndc.get(id) if err != nil { - writer.WriteHeader(http.StatusInternalServerError) - log.Error(err) + handleServerError(writer, err) return } - writeIDs("Devices", p.(*pndImplementation).devices.UUIDs()) + writeIDs(writer, "Devices", p.(*pndImplementation).devices.UUIDs()) } case "init": - writeIDs := func(typ string, ids []uuid.UUID) { - for _, id := range ids { - fmt.Fprintf(writer, "%v", id) - } + writeIDs(writer, "PNDs", c.pndc.UUIDs()) + writeIDs(writer, "SBIs", c.sbic.UUIDs()) + case "update", "replace": + if err := pnd.ChangeOND(id, apiOpmap[q], query.Get("path"), query.Get("value")); err != nil { + handleServerError(writer, err) + return } - writeIDs("PNDs", c.pndc.UUIDs()) - writeIDs("SBIs", c.sbic.UUIDs()) - case "set": - resp, err := pnd.(*pndImplementation).Set(id, query.Get("path"), query.Get("value")) - if err != nil { - writer.WriteHeader(http.StatusInternalServerError) - log.Error(err) + writer.WriteHeader(http.StatusOK) + case "delete": + if err := pnd.ChangeOND(id, TRANSPORT_DELETE, query.Get("path")); err != nil { + handleServerError(writer, err) return } writer.WriteHeader(http.StatusOK) - fmt.Fprintln(writer, resp) + case "change-list": + changes := pnd.ListCommitted() + writeIDs(writer, "Tentative changes", changes) + writer.WriteHeader(http.StatusOK) + case "change-list-pending": + changes := pnd.ListPending() + writeIDs(writer, "Pending changes", changes) + writer.WriteHeader(http.StatusOK) + case "change-commit": + cuid, err := uuid.Parse(query.Get("cuid")) + if err != nil { + handleServerError(writer, err) + return + } + change, err := pnd.Pending(cuid) + if err != nil { + handleServerError(writer, err) + return + } + change.(*Change).Commit() + writer.WriteHeader(http.StatusAccepted) + case "change-confirm": + cuid, err := uuid.Parse(query.Get("cuid")) + if err != nil { + handleServerError(writer, err) + return + } + change, err := pnd.Committed(cuid) + if err != nil { + handleServerError(writer, err) + return + } + change.(*Change).Confirm() + writer.WriteHeader(http.StatusAccepted) default: writer.WriteHeader(http.StatusBadRequest) } } + +func writeIDs(w io.Writer, typ string, ids []uuid.UUID) { + fmt.Fprintf(w, "%v:\n", typ) + for i, id := range ids { + fmt.Fprintf(w, "%v: %v\n", i+1, id) + } +} + +func handleServerError(w http.ResponseWriter, err error) { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "error: %v", err) + log.Error(err) +} diff --git a/nucleus/http_test.go b/nucleus/http_test.go index 9efa72110a1fe89cf1507424d147e7faac6fd71b..b7728d9ff87b8359a26623a56fe881ef41b6a3b3 100644 --- a/nucleus/http_test.go +++ b/nucleus/http_test.go @@ -123,7 +123,19 @@ func Test_httpApi(t *testing.T) { }, { name: "set", - request: apiEndpoint + "/api?q=set" + args + "&path=/system/config/hostname&value=ceos3000", + request: apiEndpoint + "/api?q=update" + args + "&path=/system/config/hostname&value=ceos3000", + want: &http.Response{StatusCode: http.StatusOK}, + wantErr: false, + }, + { + name: "replace", + request: apiEndpoint + "/api?q=replace" + args + "&path=/system/config/hostname&value=ceos3000", + want: &http.Response{StatusCode: http.StatusOK}, + wantErr: false, + }, + { + name: "delete", + request: apiEndpoint + "/api?q=delete" + args + "&path=/system/config/hostname", want: &http.Response{StatusCode: http.StatusOK}, wantErr: false, }, diff --git a/nucleus/initialise_test.go b/nucleus/initialise_test.go index 6c90b054e44d009e03542821ced09f46cd65bb49..932adb147fc0033dbd66557923f27ec965f9c2a4 100644 --- a/nucleus/initialise_test.go +++ b/nucleus/initialise_test.go @@ -139,20 +139,24 @@ func readTestUUIDs() { } func mockDevice() Device { + sbi := &OpenConfig{} return Device{ UUID: mdid, - GoStruct: nil, - SBI: &OpenConfig{}, + GoStruct: sbi.Schema().Root, + SBI: sbi, Transport: &mocks.Transport{}, } } func newPnd() pndImplementation { return pndImplementation{ - name: "default", - description: "default test pnd", - sbic: sbiStore{store{}}, - devices: deviceStore{store{}}, - id: defaultPndID, + name: "default", + description: "default test pnd", + sbic: sbiStore{store{}}, + devices: deviceStore{store{}}, + pendingChanges: changeStore{store{}}, + committedChanges: changeStore{store{}}, + confirmedChanges: changeStore{store{}}, + id: defaultPndID, } } diff --git a/nucleus/principalNetworkDomain.go b/nucleus/principalNetworkDomain.go index e9dba35b2885669dd7d963710e3fffd6fa307773..df77cfa866b8c2a6afeadd47ced27d348edbd242 100644 --- a/nucleus/principalNetworkDomain.go +++ b/nucleus/principalNetworkDomain.go @@ -1,6 +1,7 @@ package nucleus import ( + "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" . "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" "context" "github.com/openconfig/ygot/ygot" @@ -19,7 +20,7 @@ type PrincipalNetworkDomain interface { RemoveSbi(uuid.UUID) error AddDevice(interface{}) error GetDevice(uuid uuid.UUID) (ygot.GoStruct, error) - ChangeOND(uuid uuid.UUID, operation Operation, path string, value string) error + ChangeOND(uuid uuid.UUID, operation interface{}, path string, value ...string) error RemoveDevice(uuid.UUID) error Request(uuid.UUID, string) error RequestAll(string) error @@ -29,6 +30,10 @@ type PrincipalNetworkDomain interface { ContainsDevice(uuid.UUID) bool GetSBIs() interface{} ID() uuid.UUID + ListPending() []uuid.UUID + Pending(uuid.UUID) (interface{}, error) + ListCommitted() []uuid.UUID + Committed(uuid.UUID) (interface{}, error) } type pndImplementation struct { @@ -36,9 +41,9 @@ type pndImplementation struct { description string sbic sbiStore devices deviceStore - pendingChanges store - committedChanges store - confirmedChanges store + pendingChanges changeStore + committedChanges changeStore + confirmedChanges changeStore id uuid.UUID } @@ -49,9 +54,9 @@ func NewPND(name, description string, id uuid.UUID, sbi SouthboundInterface) (Pr description: description, sbic: sbiStore{store{}}, devices: deviceStore{store{}}, - pendingChanges: store{}, - committedChanges: store{}, - confirmedChanges: store{}, + pendingChanges: changeStore{store{}}, + committedChanges: changeStore{store{}}, + confirmedChanges: changeStore{store{}}, id: id, } if err := pnd.sbic.add(sbi); err != nil { @@ -60,6 +65,22 @@ func NewPND(name, description string, id uuid.UUID, sbi SouthboundInterface) (Pr return pnd, nil } +func (pnd *pndImplementation) ListPending() []uuid.UUID { + return pnd.pendingChanges.UUIDs() +} + +func (pnd *pndImplementation) ListCommitted() []uuid.UUID { + return pnd.committedChanges.UUIDs() +} + +func (pnd *pndImplementation)Pending(id uuid.UUID) (interface{}, error) { + return pnd.pendingChanges.get(id) +} + +func (pnd *pndImplementation)Committed(id uuid.UUID) (interface{}, error) { + return pnd.committedChanges.get(id) +} + func (pnd *pndImplementation) ID() uuid.UUID { return pnd.id } @@ -126,7 +147,7 @@ func (pnd *pndImplementation) GetDevice(uuid uuid.UUID) (ygot.GoStruct, error) { if err != nil { return nil, err } - return ygot.DeepCopy(d) + return ygot.DeepCopy(d.GoStruct) } // RemoveDevice removes a device from the PND @@ -209,13 +230,13 @@ func (pnd *pndImplementation) RequestAll(path string) error { } // ChangeOND creates a change from the provided Operation, path and value. The Change is pending and -func (pnd *pndImplementation) ChangeOND(uuid uuid.UUID, operation Operation, path string, value string) error { +func (pnd *pndImplementation) ChangeOND(uuid uuid.UUID, operation interface{}, path string, value ...string) error { d, err := pnd.getDevice(uuid) if err != nil { return err } - cpy, err := ygot.DeepCopy(d.GoStruct) + ygot.BuildEmptyTree(cpy) p, err := ygot.StringToStructuredPath(path) if err != nil { @@ -223,12 +244,9 @@ func (pnd *pndImplementation) ChangeOND(uuid uuid.UUID, operation Operation, pat } switch operation { - case TRANSPORT_UPDATE: - if err := ytypes.SetNode(d.SBI.Schema().RootSchema(), cpy, p, value); err != nil { - return err - } - case TRANSPORT_REPLACE: - if err := ytypes.SetNode(d.SBI.Schema().RootSchema(), cpy, p, value); err != nil { + case TRANSPORT_UPDATE, TRANSPORT_REPLACE: + typedValue := gnmi.TypedValue(value[0]) + if err := ytypes.SetNode(d.SBI.Schema().RootSchema(), cpy, p, typedValue); err != nil { return err } case TRANSPORT_DELETE: diff --git a/nucleus/principalNetworkDomain_test.go b/nucleus/principalNetworkDomain_test.go index f02f840bc948d4887983a4beb532808d9e8dc2c7..4b885cdf550139ee2a0410afca2c38d1025202d0 100644 --- a/nucleus/principalNetworkDomain_test.go +++ b/nucleus/principalNetworkDomain_test.go @@ -522,3 +522,47 @@ func Test_pndImplementation_RequestAll(t *testing.T) { }) } } + +func Test_pndImplementation_ChangeOND(t *testing.T) { + type fields struct { + name string + description string + sbic sbiStore + devices deviceStore + pendingChanges changeStore + committedChanges changeStore + confirmedChanges changeStore + id uuid.UUID + } + type args struct { + uuid uuid.UUID + operation interface{} + path string + value []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pnd := &pndImplementation{ + name: tt.fields.name, + description: tt.fields.description, + sbic: tt.fields.sbic, + devices: tt.fields.devices, + pendingChanges: tt.fields.pendingChanges, + committedChanges: tt.fields.committedChanges, + confirmedChanges: tt.fields.confirmedChanges, + id: tt.fields.id, + } + if err := pnd.ChangeOND(tt.args.uuid, tt.args.operation, tt.args.path, tt.args.value...); (err != nil) != tt.wantErr { + t.Errorf("ChangeOND() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} \ No newline at end of file diff --git a/nucleus/restconf_transport.go b/nucleus/restconf_transport.go index 7afdd8868d71f499463325532318f5f5874960a5..e1ae9fad723e70552e86562f759ee76fc3854f83 100644 --- a/nucleus/restconf_transport.go +++ b/nucleus/restconf_transport.go @@ -1,7 +1,6 @@ package nucleus import ( - "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" "context" "github.com/openconfig/ygot/ytypes" ) @@ -38,9 +37,4 @@ func (r Restconf) GetOptions() interface{} { // ProcessResponse not yet implemented func (r Restconf) ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error { return &ErrNotYetImplemented{} -} - -// TranslateChange not yet implemented -func (r Restconf) TranslateChange(i ...interface{}) (*pnd.Change, error) { - return nil, &ErrNotYetImplemented{} -} +} \ No newline at end of file diff --git a/nucleus/restconf_transport_test.go b/nucleus/restconf_transport_test.go index 5f1eb1e352f2cb8214686c5215eea419c465dcd4..b31df33d665563cb12c64aac28f98788454e7272 100644 --- a/nucleus/restconf_transport_test.go +++ b/nucleus/restconf_transport_test.go @@ -61,26 +61,21 @@ func TestRestconf_ProcessResponse(t *testing.T) { func TestRestconf_Set(t *testing.T) { type args struct { ctx context.Context - params []string + params []interface{} } tests := []struct { name string args args - want interface{} wantErr bool }{ - {name: "not implemented", args: args{}, want: nil, wantErr: true}, + {name: "not implemented", args: args{}, wantErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := Restconf{} - got, err := r.Set(tt.args.ctx, tt.args.params...) + err := r.Set(tt.args.ctx, tt.args.params...) if (err != nil) != tt.wantErr { t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Set() got = %v, want %v", got, tt.want) } }) } diff --git a/nucleus/store.go b/nucleus/store.go index 0563a5a30533467809380ac25d949bfc4b578e68..aeed8cb8f11e176d75878c1657e3f1c83f9f388a 100644 --- a/nucleus/store.go +++ b/nucleus/store.go @@ -1,6 +1,7 @@ package nucleus import ( + . "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" "github.com/google/uuid" log "github.com/sirupsen/logrus" "reflect" @@ -131,7 +132,7 @@ func (s deviceStore) get(id uuid.UUID) (*Device, error) { if !ok { return nil, &ErrInvalidTypeAssertion{ v: device, - t: "Device", + t: reflect.TypeOf(&Device{}), } } log.WithFields(log.Fields{ @@ -139,3 +140,25 @@ func (s deviceStore) get(id uuid.UUID) (*Device, error) { }).Debug("device was accessed") return device, nil } + +type changeStore struct { + store +} + +func (s changeStore) get(id uuid.UUID) (*Change, error) { + item, err := s.store.get(id) + if err != nil { + return nil, err + } + change, ok := item.(*Change) + if !ok { + return nil, &ErrInvalidTypeAssertion{ + v: change, + t: reflect.TypeOf(&Change{}), + } + } + log.WithFields(log.Fields{ + "uuid": id, + }).Debug("change was accessed") + return change, nil +} diff --git a/nucleus/transport.go b/nucleus/transport.go index 17ab0f82af2011c342b772c08df1e997fc2fe308..2d9313d591acb6e66667d20f1abf81deca3daeaf 100644 --- a/nucleus/transport.go +++ b/nucleus/transport.go @@ -2,7 +2,6 @@ package nucleus import ( "bytes" - "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" "context" "github.com/openconfig/ygot/ytypes" "io" @@ -26,7 +25,6 @@ type Transport interface { Type() string GetOptions() interface{} ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error - TranslateChange(...interface{}) (*pnd.Change, error) } // YANGConsumer is a auxillary type to redirect the response diff --git a/test/integration/nucleusIntegration_test.go b/test/integration/nucleusIntegration_test.go index 816888d6f77f857225f34d22b794017efe641629..960623c1de8b373cf0f4790220e876abb21fc49e 100644 --- a/test/integration/nucleusIntegration_test.go +++ b/test/integration/nucleusIntegration_test.go @@ -23,13 +23,12 @@ func TestGnmi_SetIntegration(t *testing.T) { } type args struct { ctx context.Context - params []interface{} + params []string } tests := []struct { name string fields fields args args - want interface{} wantErr bool }{ { @@ -42,9 +41,8 @@ func TestGnmi_SetIntegration(t *testing.T) { }, args: args{ ctx: context.Background(), - params: []interface{}{&gnmi.Operation{}}, + params: []string{}, }, - want: nil, wantErr: true, }, { @@ -52,21 +50,8 @@ func TestGnmi_SetIntegration(t *testing.T) { fields: fields{opt: opt}, args: args{ ctx: context.Background(), - params: []interface{}{ - &gnmi.Operation{ - Type: "update", - Origin: "", - Target: "", - Path: []string{ - "system", - "config", - "hostname", - }, - Val: "ceos3000", - }, + params: []string{"/system/config/hostname", "ceos3000"}, }, - }, - want: gnmiMessages["../proto/resp-set-system-config-hostname"], wantErr: false, }, } @@ -77,21 +62,11 @@ func TestGnmi_SetIntegration(t *testing.T) { t.Errorf("NewGnmiTransport() error = %v, wantErr %v", err, tt.wantErr) return } - resp, err := g.Set(tt.args.ctx, tt.args.params...) + err = g.Set(tt.args.ctx, tt.args.params) if (err != nil) != tt.wantErr { t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) return } - got, ok := resp.(*gpb.SetResponse) - if !ok { - t.Errorf("want: %v, got %v, error: %v", reflect.TypeOf(&gpb.SetResponse{}), reflect.TypeOf(resp), &nucleus.ErrInvalidTypeAssertion{}) - } - if err != nil && tt.wantErr { - return - } else if got.Prefix.Target != testAddress || - got.Response[0].Op != gpb.UpdateResult_UPDATE { - t.Errorf("Set() got = %v, want %v", got, tt.want) - } }) } }