From ad7782cbf83c11f152a6457f3808a4da99a1ae56 Mon Sep 17 00:00:00 2001 From: Eric Multanen Date: Thu, 28 May 2020 17:07:20 -0700 Subject: Create OVN network action controller from ncm Split out part of ncm microservice to act as the Onv4k8s network action controller for the orchestrator. No code changes really - just moving around to fit the architectural plan. Issue-ID: MULTICLOUD-1029 Signed-off-by: Eric Multanen Change-Id: I17292ac72d041050269f05fc4a0c2a6ca741aeb5 --- src/Makefile | 4 + src/ncm/api/api.go | 65 --- src/ncm/api/chainhandler.go | 290 ---------- src/ncm/api/chainhandler_test.go | 56 -- src/ncm/api/netcontrolintenthandler.go | 230 -------- src/ncm/api/workloadifintenthandler.go | 251 --------- src/ncm/api/workloadintenthandler.go | 218 ------- src/ncm/cmd/main.go | 58 -- src/ncm/go.mod | 2 + .../contextupdateserver/contextupdateserver.go | 45 -- src/ncm/pkg/grpc/register.go | 58 -- src/ncm/pkg/module/chaining.go | 209 ------- src/ncm/pkg/module/module.go | 8 - src/ncm/pkg/module/module_definitions.go | 3 - src/ncm/pkg/module/netcontrolintent.go | 295 ---------- src/ncm/pkg/module/resources.go | 273 --------- src/ncm/pkg/module/workloadifintent.go | 188 ------- src/ncm/pkg/module/workloadintent.go | 181 ------ src/orchestrator/go.sum | 2 + src/ovnaction/Makefile | 36 ++ src/ovnaction/api/api.go | 113 ++++ src/ovnaction/api/chainhandler.go | 290 ++++++++++ src/ovnaction/api/chainhandler_test.go | 56 ++ src/ovnaction/api/netcontrolintenthandler.go | 232 ++++++++ src/ovnaction/api/workloadifintenthandler.go | 251 +++++++++ src/ovnaction/api/workloadintenthandler.go | 218 +++++++ src/ovnaction/cmd/main.go | 134 +++++ src/ovnaction/config.json | 10 + src/ovnaction/go.mod | 36 ++ src/ovnaction/go.sum | 626 +++++++++++++++++++++ .../contextupdateserver/contextupdateserver.go | 45 ++ src/ovnaction/pkg/grpc/register.go | 58 ++ src/ovnaction/pkg/module/chaining.go | 209 +++++++ src/ovnaction/pkg/module/module.go | 37 ++ src/ovnaction/pkg/module/module_definitions.go | 68 +++ src/ovnaction/pkg/module/netcontrolintent.go | 295 ++++++++++ src/ovnaction/pkg/module/resources.go | 273 +++++++++ src/ovnaction/pkg/module/workloadifintent.go | 188 +++++++ src/ovnaction/pkg/module/workloadintent.go | 181 ++++++ src/ovnaction/scripts/Dockerfile | 30 + 40 files changed, 3394 insertions(+), 2428 deletions(-) delete mode 100644 src/ncm/api/chainhandler.go delete mode 100644 src/ncm/api/chainhandler_test.go delete mode 100644 src/ncm/api/netcontrolintenthandler.go delete mode 100644 src/ncm/api/workloadifintenthandler.go delete mode 100644 src/ncm/api/workloadintenthandler.go delete mode 100644 src/ncm/pkg/grpc/contextupdateserver/contextupdateserver.go delete mode 100644 src/ncm/pkg/grpc/register.go delete mode 100644 src/ncm/pkg/module/chaining.go delete mode 100644 src/ncm/pkg/module/netcontrolintent.go delete mode 100644 src/ncm/pkg/module/resources.go delete mode 100644 src/ncm/pkg/module/workloadifintent.go delete mode 100644 src/ncm/pkg/module/workloadintent.go create mode 100644 src/ovnaction/Makefile create mode 100644 src/ovnaction/api/api.go create mode 100644 src/ovnaction/api/chainhandler.go create mode 100644 src/ovnaction/api/chainhandler_test.go create mode 100644 src/ovnaction/api/netcontrolintenthandler.go create mode 100644 src/ovnaction/api/workloadifintenthandler.go create mode 100644 src/ovnaction/api/workloadintenthandler.go create mode 100644 src/ovnaction/cmd/main.go create mode 100644 src/ovnaction/config.json create mode 100644 src/ovnaction/go.mod create mode 100644 src/ovnaction/go.sum create mode 100644 src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go create mode 100644 src/ovnaction/pkg/grpc/register.go create mode 100644 src/ovnaction/pkg/module/chaining.go create mode 100644 src/ovnaction/pkg/module/module.go create mode 100644 src/ovnaction/pkg/module/module_definitions.go create mode 100644 src/ovnaction/pkg/module/netcontrolintent.go create mode 100644 src/ovnaction/pkg/module/resources.go create mode 100644 src/ovnaction/pkg/module/workloadifintent.go create mode 100644 src/ovnaction/pkg/module/workloadintent.go create mode 100644 src/ovnaction/scripts/Dockerfile (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 456678cb..e97b0982 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,6 +5,7 @@ build: $(MAKE) -C ncm build $(MAKE) -C dcm build $(MAKE) -C rsync build + $(MAKE) -C ovnaction build deploy: $(MAKE) -C monitor deploy @@ -13,6 +14,7 @@ deploy: $(MAKE) -C ncm deploy $(MAKE) -C dcm deploy $(MAKE) -C rsync deploy + $(MAKE) -C ovnaction deploy all: $(MAKE) -C monitor all @@ -21,6 +23,7 @@ all: $(MAKE) -C ncm all $(MAKE) -C dcm all $(MAKE) -C rsync all + $(MAKE) -C ovnaction all clean: $(MAKE) -C monitor clean @@ -29,3 +32,4 @@ clean: $(MAKE) -C ncm clean $(MAKE) -C dcm clean $(MAKE) -C rsync clean + $(MAKE) -C ovnaction clean diff --git a/src/ncm/api/api.go b/src/ncm/api/api.go index 29ed46bd..2b9c1b17 100644 --- a/src/ncm/api/api.go +++ b/src/ncm/api/api.go @@ -51,34 +51,6 @@ func setClient(client, testClient interface{}) interface{} { return c } } - case *moduleLib.NetControlIntentClient: - if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.NetControlIntentManager)(nil)).Elem()) { - c, ok := testClient.(moduleLib.NetControlIntentManager) - if ok { - return c - } - } - case *moduleLib.WorkloadIntentClient: - if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.WorkloadIntentManager)(nil)).Elem()) { - c, ok := testClient.(moduleLib.WorkloadIntentManager) - if ok { - return c - } - } - case *moduleLib.WorkloadIfIntentClient: - if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.WorkloadIfIntentManager)(nil)).Elem()) { - c, ok := testClient.(moduleLib.WorkloadIfIntentManager) - if ok { - return c - } - } - case *moduleLib.ChainClient: - if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.ChainManager)(nil)).Elem()) { - c, ok := testClient.(moduleLib.ChainManager) - if ok { - return c - } - } default: fmt.Printf("unknown type %T\n", cl) } @@ -134,42 +106,5 @@ func NewRouter(testClient interface{}) *mux.Router { router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/provider-networks/{name}", providernetHandler.getProviderNetHandler).Methods("GET") router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/provider-networks/{name}", providernetHandler.deleteProviderNetHandler).Methods("DELETE") - netcontrolintentHandler := netcontrolintentHandler{ - client: setClient(moduleClient.NetControlIntent, testClient).(moduleLib.NetControlIntentManager), - } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.deleteHandler).Methods("DELETE") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}/apply", netcontrolintentHandler.applyHandler).Methods("POST") - - workloadintentHandler := workloadintentHandler{ - client: setClient(moduleClient.WorkloadIntent, testClient).(moduleLib.WorkloadIntentManager), - } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.deleteHandler).Methods("DELETE") - - workloadifintentHandler := workloadifintentHandler{ - client: setClient(moduleClient.WorkloadIfIntent, testClient).(moduleLib.WorkloadIfIntentManager), - } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.deleteHandler).Methods("DELETE") - - chainHandler := chainHandler{ - client: setClient(moduleClient.Chain, testClient).(moduleLib.ChainManager), - } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.deleteHandler).Methods("DELETE") - return router } diff --git a/src/ncm/api/chainhandler.go b/src/ncm/api/chainhandler.go deleted file mode 100644 index 7169014b..00000000 --- a/src/ncm/api/chainhandler.go +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package api - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - - moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" - pkgerrors "github.com/pkg/errors" - - "github.com/gorilla/mux" -) - -// Used to store backend implementations objects -// Also simplifies mocking for unit testing purposes -type chainHandler struct { - // Interface that implements workload intent operations - // We will set this variable with a mock interface for testing - client moduleLib.ChainManager -} - -func validateRoutingNetwork(r moduleLib.RoutingNetwork) error { - errs := validation.IsValidName(r.NetworkName) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid routing network name: %v", errs) - } - - err := validation.IsIpv4Cidr(r.Subnet) - if err != nil { - return pkgerrors.Wrap(err, "Invalid routing network subnet") - } - - err = validation.IsIpv4(r.GatewayIP) - if err != nil { - return pkgerrors.Wrap(err, "Invalid routing network gateway IP") - } - - return nil -} - -// validateNetworkChain checks that the network chain string input follows the -// generic format: "app=app1,net1,app=app2,net2, ..... ,netN-1,app=appN" -// assume "app=app1" can conform to validation.IsValidLabel() with an "=" -func validateNetworkChain(chain string) error { - elems := strings.Split(chain, ",") - - // chain needs at least two apps and a network - if len(elems) < 3 { - return pkgerrors.Errorf("Network chain is too short") - } - - // chain needs to have an odd number of elements - if len(elems)%2 == 0 { - return pkgerrors.Errorf("Invalid network chain - even number of elements") - } - - for i, s := range elems { - // allows whitespace in comma separated elements - t := strings.TrimSpace(s) - // if even element, verify a=b format - if i%2 == 0 { - if strings.Index(t, "=") < 1 { - return pkgerrors.Errorf("Invalid deployment label element of network chain") - } - errs := validation.IsValidLabel(t) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid deployment label element: %v", errs) - } - } else { - errs := validation.IsValidName(t) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid network element of network chain: %v", errs) - } - } - } - return nil -} - -// Check for valid format of input parameters -func validateChainInputs(ch moduleLib.Chain) error { - // validate metadata - err := moduleLib.IsValidMetadata(ch.Metadata) - if err != nil { - return pkgerrors.Wrap(err, "Invalid network chain metadata") - } - - if strings.ToLower(ch.Spec.ChainType) != moduleLib.RoutingChainType { - return pkgerrors.Wrap(err, "Invalid network chain type") - } - - for _, r := range ch.Spec.RoutingSpec.LeftNetwork { - err = validateRoutingNetwork(r) - if err != nil { - return err - } - } - - for _, r := range ch.Spec.RoutingSpec.RightNetwork { - err = validateRoutingNetwork(r) - if err != nil { - return err - } - } - - err = validateNetworkChain(ch.Spec.RoutingSpec.NetworkChain) - if err != nil { - return err - } - - errs := validation.IsValidName(ch.Spec.RoutingSpec.Namespace) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid network chain route spec namespace: %v", errs) - } - - return nil -} - -// Create handles creation of the Chain entry in the database -func (h chainHandler) createHandler(w http.ResponseWriter, r *http.Request) { - var ch moduleLib.Chain - vars := mux.Vars(r) - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := json.NewDecoder(r.Body).Decode(&ch) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if ch.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - err = validateChainInputs(ch) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, false) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Put handles creation/update of the Chain entry in the database -func (h chainHandler) putHandler(w http.ResponseWriter, r *http.Request) { - var ch moduleLib.Chain - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := json.NewDecoder(r.Body).Decode(&ch) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if ch.Metadata.Name == "" { - http.Error(w, "Missing name in PUT request", http.StatusBadRequest) - return - } - - // Name in URL should match name in body - if ch.Metadata.Name != name { - fmt.Printf("bodyname = %v, name= %v\n", ch.Metadata.Name, name) - http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) - return - } - - err = validateChainInputs(ch) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, true) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Get handles GET operations on a particular Chain Name -// Returns a Chain -func (h chainHandler) getHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - var ret interface{} - var err error - - if len(name) == 0 { - ret, err = h.client.GetChains(project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetChain(name, project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Delete handles DELETE operations on a particular Chain -func (h chainHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := h.client.DeleteChain(name, project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/src/ncm/api/chainhandler_test.go b/src/ncm/api/chainhandler_test.go deleted file mode 100644 index f13a90c4..00000000 --- a/src/ncm/api/chainhandler_test.go +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package api - -import ( - "testing" -) - -func TestIsValidNetworkChain(t *testing.T) { - t.Run("Valid Chains", func(t *testing.T) { - validchains := []string{ - "app=abc,net1,app=xyz", - "app=abc, net1, app=xyz", - " app=abc , net1 , app=xyz ", - "app.kubernets.io/name=abc,net1,app.kubernets.io/name=xyz", - "app.kubernets.io/name=abc,net1,app.kubernets.io/name=xyz, net2, anotherlabel=wex", - } - for _, chain := range validchains { - err := validateNetworkChain(chain) - if err != nil { - t.Errorf("Valid network chain failed to pass: %v %v", chain, err) - } - } - }) - - t.Run("Invalid Chains", func(t *testing.T) { - invalidchains := []string{ - "", - "app=abc,net1,app= xyz", - "app=abc,net1,xyz", - "app=abc,net1", - "app.kubernets.io/name=abc,net1,=xyz", - "abcdefg", - } - for _, chain := range invalidchains { - err := validateNetworkChain(chain) - if err == nil { - t.Errorf("Invalid network chain passed: %v", chain) - } - } - }) -} diff --git a/src/ncm/api/netcontrolintenthandler.go b/src/ncm/api/netcontrolintenthandler.go deleted file mode 100644 index 48ef1de2..00000000 --- a/src/ncm/api/netcontrolintenthandler.go +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package api - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - - moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" - pkgerrors "github.com/pkg/errors" - - "github.com/gorilla/mux" -) - -// Used to store backend implementations objects -// Also simplifies mocking for unit testing purposes -type netcontrolintentHandler struct { - // Interface that implements Cluster operations - // We will set this variable with a mock interface for testing - client moduleLib.NetControlIntentManager -} - -// Check for valid format of input parameters -func validateNetControlIntentInputs(nci moduleLib.NetControlIntent) error { - // validate metadata - err := moduleLib.IsValidMetadata(nci.Metadata) - if err != nil { - return pkgerrors.Wrap(err, "Invalid network controller intent metadata") - } - return nil -} - -// Create handles creation of the NetControlIntent entry in the database -func (h netcontrolintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { - var nci moduleLib.NetControlIntent - vars := mux.Vars(r) - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - - err := json.NewDecoder(r.Body).Decode(&nci) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if nci.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - err = validateNetControlIntentInputs(nci) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, false) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Put handles creation/update of the NetControlIntent entry in the database -func (h netcontrolintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { - var nci moduleLib.NetControlIntent - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - - err := json.NewDecoder(r.Body).Decode(&nci) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if nci.Metadata.Name == "" { - http.Error(w, "Missing name in PUT request", http.StatusBadRequest) - return - } - - // Name in URL should match name in body - if nci.Metadata.Name != name { - fmt.Printf("bodyname = %v, name= %v\n", nci.Metadata.Name, name) - http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) - return - } - - err = validateNetControlIntentInputs(nci) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, true) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Get handles GET operations on a particular NetControlIntent Name -// Returns a NetControlIntent -func (h netcontrolintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - var ret interface{} - var err error - - if len(name) == 0 { - ret, err = h.client.GetNetControlIntents(project, compositeApp, compositeAppVersion) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetNetControlIntent(name, project, compositeApp, compositeAppVersion) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Delete handles DELETE operations on a particular NetControlIntent Name -func (h netcontrolintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - - err := h.client.DeleteNetControlIntent(name, project, compositeApp, compositeAppVersion) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} - -// Apply handles POST operations to Apply a particular NetControlIntent to the App Context -func (h netcontrolintentHandler) applyHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - - var aci struct { - AppContextId string `json:"appContextId"` - } - - err := json.NewDecoder(r.Body).Decode(&aci) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - err = h.client.ApplyNetControlIntent(name, project, compositeApp, compositeAppVersion, aci.AppContextId) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/src/ncm/api/workloadifintenthandler.go b/src/ncm/api/workloadifintenthandler.go deleted file mode 100644 index 31472a5d..00000000 --- a/src/ncm/api/workloadifintenthandler.go +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package api - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - - moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" - pkgerrors "github.com/pkg/errors" - - "github.com/gorilla/mux" -) - -// Used to store backend implementations objects -// Also simplifies mocking for unit testing purposes -type workloadifintentHandler struct { - // Interface that implements workload intent operations - // We will set this variable with a mock interface for testing - client moduleLib.WorkloadIfIntentManager -} - -// Check for valid format of input parameters -func validateWorkloadIfIntentInputs(wif moduleLib.WorkloadIfIntent) error { - // validate metadata - err := moduleLib.IsValidMetadata(wif.Metadata) - if err != nil { - return pkgerrors.Wrap(err, "Invalid network controller intent metadata") - } - - errs := validation.IsValidName(wif.Spec.IfName) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid interface name = [%v], errors: %v", wif.Spec.IfName, errs) - } - - errs = validation.IsValidName(wif.Spec.NetworkName) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid network name = [%v], errors: %v", wif.Spec.NetworkName, errs) - } - - // optional - only validate if supplied - if len(wif.Spec.DefaultGateway) > 0 { - errs = validation.IsValidName(wif.Spec.DefaultGateway) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid default interface = [%v], errors: %v", wif.Spec.DefaultGateway, errs) - } - } - - // optional - only validate if supplied - if len(wif.Spec.IpAddr) > 0 { - err = validation.IsIp(wif.Spec.IpAddr) - if err != nil { - return pkgerrors.Errorf("Invalid IP address = [%v], errors: %v", wif.Spec.IpAddr, err) - } - } - - // optional - only validate if supplied - if len(wif.Spec.MacAddr) > 0 { - err = validation.IsMac(wif.Spec.MacAddr) - if err != nil { - return pkgerrors.Errorf("Invalid MAC address = [%v], errors: %v", wif.Spec.MacAddr, err) - } - } - return nil -} - -// Create handles creation of the Network entry in the database -func (h workloadifintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { - var wif moduleLib.WorkloadIfIntent - vars := mux.Vars(r) - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - workloadIntent := vars["workload-intent"] - - err := json.NewDecoder(r.Body).Decode(&wif) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if wif.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - // set default value - if len(wif.Spec.DefaultGateway) == 0 { - wif.Spec.DefaultGateway = "false" // set default value - } - - err = validateWorkloadIfIntentInputs(wif) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, false) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Put handles creation/update of the Network entry in the database -func (h workloadifintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { - var wif moduleLib.WorkloadIfIntent - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - workloadIntent := vars["workload-intent"] - - err := json.NewDecoder(r.Body).Decode(&wif) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if wif.Metadata.Name == "" { - http.Error(w, "Missing name in PUT request", http.StatusBadRequest) - return - } - - // Name in URL should match name in body - if wif.Metadata.Name != name { - fmt.Printf("bodyname = %v, name= %v\n", wif.Metadata.Name, name) - http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) - return - } - - // set default value - if len(wif.Spec.DefaultGateway) == 0 { - wif.Spec.DefaultGateway = "false" // set default value - } - - err = validateWorkloadIfIntentInputs(wif) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, true) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Get handles GET operations on a particular Network Name -// Returns a Network -func (h workloadifintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - workloadIntent := vars["workload-intent"] - var ret interface{} - var err error - - if len(name) == 0 { - ret, err = h.client.GetWorkloadIfIntents(project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Delete handles DELETE operations on a particular Network Name -func (h workloadifintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - workloadIntent := vars["workload-intent"] - - err := h.client.DeleteWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/src/ncm/api/workloadintenthandler.go b/src/ncm/api/workloadintenthandler.go deleted file mode 100644 index f1d0093d..00000000 --- a/src/ncm/api/workloadintenthandler.go +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package api - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - - moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" - pkgerrors "github.com/pkg/errors" - - "github.com/gorilla/mux" -) - -// Used to store backend implementations objects -// Also simplifies mocking for unit testing purposes -type workloadintentHandler struct { - // Interface that implements workload intent operations - // We will set this variable with a mock interface for testing - client moduleLib.WorkloadIntentManager -} - -// Check for valid format of input parameters -func validateWorkloadIntentInputs(wi moduleLib.WorkloadIntent) error { - // validate metadata - err := moduleLib.IsValidMetadata(wi.Metadata) - if err != nil { - return pkgerrors.Wrap(err, "Invalid network controller intent metadata") - } - - errs := validation.IsValidName(wi.Spec.AppName) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid application name = [%v], errors: %v", wi.Spec.AppName, errs) - } - - errs = validation.IsValidName(wi.Spec.WorkloadResource) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid workload resource = [%v], errors: %v", wi.Spec.WorkloadResource, errs) - } - - errs = validation.IsValidName(wi.Spec.Type) - if len(errs) > 0 { - return pkgerrors.Errorf("Invalid workload type = [%v], errors: %v", wi.Spec.Type, errs) - } - return nil -} - -// Create handles creation of the Network entry in the database -func (h workloadintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { - var wi moduleLib.WorkloadIntent - vars := mux.Vars(r) - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := json.NewDecoder(r.Body).Decode(&wi) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if wi.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - err = validateWorkloadIntentInputs(wi) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, false) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Put handles creation/update of the Network entry in the database -func (h workloadintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { - var wi moduleLib.WorkloadIntent - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := json.NewDecoder(r.Body).Decode(&wi) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - // Name is required. - if wi.Metadata.Name == "" { - http.Error(w, "Missing name in PUT request", http.StatusBadRequest) - return - } - - // Name in URL should match name in body - if wi.Metadata.Name != name { - fmt.Printf("bodyname = %v, name= %v\n", wi.Metadata.Name, name) - http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) - return - } - - err = validateWorkloadIntentInputs(wi) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, true) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Get handles GET operations on a particular Network Name -// Returns a Network -func (h workloadintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - var ret interface{} - var err error - - if len(name) == 0 { - ret, err = h.client.GetWorkloadIntents(project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(ret) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// Delete handles DELETE operations on a particular Network Name -func (h workloadintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - netControlIntent := vars["net-control-intent"] - - err := h.client.DeleteWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/src/ncm/cmd/main.go b/src/ncm/cmd/main.go index 49af81ee..640fa3ea 100644 --- a/src/ncm/cmd/main.go +++ b/src/ncm/cmd/main.go @@ -15,72 +15,21 @@ package main import ( "context" - "fmt" "log" "math/rand" - "net" "net/http" "os" "os/signal" - "strings" "time" "github.com/gorilla/handlers" "github.com/onap/multicloud-k8s/src/ncm/api" - register "github.com/onap/multicloud-k8s/src/ncm/pkg/grpc" - "github.com/onap/multicloud-k8s/src/ncm/pkg/grpc/contextupdateserver" - updatepb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/contextupdate" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/auth" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/config" contextDb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/contextdb" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/testdata" ) -func startGrpcServer() error { - var tls bool - - if strings.Contains(config.GetConfiguration().GrpcEnableTLS, "enable") { - tls = true - } else { - tls = false - } - certFile := config.GetConfiguration().GrpcServerCert - keyFile := config.GetConfiguration().GrpcServerKey - - host, port := register.GetServerHostPort() - - lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) - if err != nil { - log.Fatalf("Could not listen to port: %v", err) - } - var opts []grpc.ServerOption - if tls { - if certFile == "" { - certFile = testdata.Path("server.pem") - } - if keyFile == "" { - keyFile = testdata.Path("server.key") - } - creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) - if err != nil { - log.Fatalf("Could not generate credentials %v", err) - } - opts = []grpc.ServerOption{grpc.Creds(creds)} - } - grpcServer := grpc.NewServer(opts...) - updatepb.RegisterContextupdateServer(grpcServer, contextupdateserver.NewContextupdateServer()) - - log.Println("Starting Network Configuration Manager gRPC Server") - err = grpcServer.Serve(lis) - if err != nil { - log.Fatalf("ncm grpc server is not serving %v", err) - } - return err -} - func main() { rand.Seed(time.Now().UnixNano()) @@ -106,13 +55,6 @@ func main() { Addr: ":" + config.GetConfiguration().ServicePort, } - go func() { - err := startGrpcServer() - if err != nil { - log.Fatalf("GRPC server failed to start") - } - }() - connectionsClose := make(chan struct{}) go func() { c := make(chan os.Signal, 1) diff --git a/src/ncm/go.mod b/src/ncm/go.mod index d9fde682..41f2b5ff 100644 --- a/src/ncm/go.mod +++ b/src/ncm/go.mod @@ -8,6 +8,7 @@ require ( github.com/gorilla/mux v1.6.2 github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20200127152046-0ee521d56061 github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200527175204-ef27eb4d63f1 + github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200529003854-0a7bf256bde5 github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pkg/errors v0.8.1 github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect @@ -23,6 +24,7 @@ require ( replace ( github.com/onap/multicloud-k8s/src/orchestrator => ../orchestrator + github.com/onap/multicloud-k8s/src/rsync => ../rsync k8s.io/api => k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d diff --git a/src/ncm/pkg/grpc/contextupdateserver/contextupdateserver.go b/src/ncm/pkg/grpc/contextupdateserver/contextupdateserver.go deleted file mode 100644 index fc548ccc..00000000 --- a/src/ncm/pkg/grpc/contextupdateserver/contextupdateserver.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2020 Intel Corporation. -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 contextupdateserver - -import ( - "context" - "encoding/json" - "log" - - contextpb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/contextupdate" - //"google.golang.org/grpc/codes" - //"google.golang.org/grpc/status" -) - -type contextupdateServer struct { - contextpb.UnimplementedContextupdateServer -} - -func (cs *contextupdateServer) UpdateAppContext(ctx context.Context, req *contextpb.ContextUpdateRequest) (*contextpb.ContextUpdateResponse, error) { - contextUpdateReq, _ := json.Marshal(req) - log.Println("GRPC Server received contextupdateRequest: ", string(contextUpdateReq)) - - // Insert call to Server Functionality here - // - // - - return &contextpb.ContextUpdateResponse{AppContextUpdated: true}, nil -} - -// NewContextUpdateServer exported -func NewContextupdateServer() *contextupdateServer { - s := &contextupdateServer{} - return s -} diff --git a/src/ncm/pkg/grpc/register.go b/src/ncm/pkg/grpc/register.go deleted file mode 100644 index 07d8f5c0..00000000 --- a/src/ncm/pkg/grpc/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2020 Intel Corporation. -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 grpc - -import ( - "os" - "strconv" - "strings" - - log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" -) - -const default_host = "localhost" -const default_port = 9030 -const default_ncm_name = "ncm" -const ENV_NCM_NAME = "NCM_NAME" - -func GetServerHostPort() (string, int) { - - // expect name of this ncm program to be in env variable "NCM_NAME" - e.g. NCM_NAME="ncm" - serviceName := os.Getenv(ENV_NCM_NAME) - if serviceName == "" { - serviceName = default_ncm_name - log.Info("Using default name for NCM service name", log.Fields{ - "Name": serviceName, - }) - } - - // expect service name to be in env variable - e.g. NCM_SERVICE_HOST - host := os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_HOST") - if host == "" { - host = default_host - log.Info("Using default host for ncm gRPC controller", log.Fields{ - "Host": host, - }) - } - - // expect service port to be in env variable - e.g. NCM_SERVICE_PORT - port, err := strconv.Atoi(os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_PORT")) - if err != nil || port < 0 { - port = default_port - log.Info("Using default port for ncm gRPC controller", log.Fields{ - "Port": port, - }) - } - return host, port -} diff --git a/src/ncm/pkg/module/chaining.go b/src/ncm/pkg/module/chaining.go deleted file mode 100644 index 45f061fa..00000000 --- a/src/ncm/pkg/module/chaining.go +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package module - -import ( - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - - pkgerrors "github.com/pkg/errors" -) - -// Chain defines the high level structure of a network chain document -type Chain struct { - Metadata Metadata `json:"metadata" yaml:"metadata"` - Spec NetworkChainingSpec `json:"spec" yaml:"spec"` -} - -// NetworkChainingSpec contains the specification of a network chain -type NetworkChainingSpec struct { - ChainType string `json:"type"` - RoutingSpec RouteSpec `json:"routingSpec"` -} - -// RouteSpec contains the routing specificaiton of a network chain -type RouteSpec struct { - LeftNetwork []RoutingNetwork `json:"leftNetwork"` - RightNetwork []RoutingNetwork `json:"rightNetwork"` - NetworkChain string `json:"networkChain"` - Namespace string `json:"namespace"` -} - -// RoutingNetwork contains the route networkroute network details for en element of a network chain -type RoutingNetwork struct { - NetworkName string `json:"networkName"` - GatewayIP string `json:"gatewayIp"` - Subnet string `json:"subnet"` -} - -// ChainKey is the key structure that is used in the database -type ChainKey struct { - Project string `json:"project"` - CompositeApp string `json:"compositeapp"` - CompositeAppVersion string `json:"compositeappversion"` - NetControlIntent string `json:"netcontrolintent"` - NetworkChain string `json:"networkchain"` -} - -// CrChain is the structure for the Network Chain Custom Resource -type CrChain struct { - APIVersion string `yaml:"apiVersion"` - Kind string `yaml:"kind"` - Chain Chain -} - -// RoutingChainType is currently only defined chaining type -const RoutingChainType = "routing" - -// ChainingAPIVersion is the kubernetes version of a network chain custom resource -const ChainingAPIVersion = "k8s.plugin.opnfv.org/v1" - -// ChainingKind is the Kind string for a network chain -const ChainingKind = "NetworkChaining" - -// ChainManager is an interface exposing the Chain functionality -type ChainManager interface { - CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) - GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) - GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) - DeleteChain(name, pr, ca, caver, netctrlint string) error -} - -// ChainClient implements the Manager -// It will also be used to maintain some localized state -type ChainClient struct { - db ClientDbInfo -} - -// NewChainClient returns an instance of the ChainClient -// which implements the Manager -func NewChainClient() *ChainClient { - return &ChainClient{ - db: ClientDbInfo{ - storeName: "orchestrator", - tagMeta: "chainmetadata", - }, - } -} - -// CreateChain - create a new Chain -func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) { - //Construct key and tag to select the entry - key := ChainKey{ - Project: pr, - CompositeApp: ca, - CompositeAppVersion: caver, - NetControlIntent: netctrlint, - NetworkChain: ch.Metadata.Name, - } - - //Check if the Network Control Intent exists - _, err := NewNetControlIntentClient().GetNetControlIntent(netctrlint, pr, ca, caver) - if err != nil { - return Chain{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netctrlint) - } - - //Check if this Chain already exists - _, err = v.GetChain(ch.Metadata.Name, pr, ca, caver, netctrlint) - if err == nil && !exists { - return Chain{}, pkgerrors.New("Chain already exists") - } - - err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, ch) - if err != nil { - return Chain{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return ch, nil -} - -// GetChain returns the Chain for corresponding name -func (v *ChainClient) GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) { - //Construct key and tag to select the entry - key := ChainKey{ - Project: pr, - CompositeApp: ca, - CompositeAppVersion: caver, - NetControlIntent: netctrlint, - NetworkChain: name, - } - - value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return Chain{}, pkgerrors.Wrap(err, "Get Chain") - } - - //value is a byte array - if value != nil { - ch := Chain{} - err = db.DBconn.Unmarshal(value[0], &ch) - if err != nil { - return Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - return ch, nil - } - - return Chain{}, pkgerrors.New("Error getting Chain") -} - -// GetChains returns all of the Chains for for the given network control intent -func (v *ChainClient) GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) { - //Construct key and tag to select the entry - key := ChainKey{ - Project: pr, - CompositeApp: ca, - CompositeAppVersion: caver, - NetControlIntent: netctrlint, - NetworkChain: "", - } - - var resp []Chain - values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return []Chain{}, pkgerrors.Wrap(err, "Get Chains") - } - - for _, value := range values { - cp := Chain{} - err = db.DBconn.Unmarshal(value, &cp) - if err != nil { - return []Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - resp = append(resp, cp) - } - - return resp, nil -} - -// DeleteChain deletes the Chain from the database -func (v *ChainClient) DeleteChain(name, pr, ca, caver, netctrlint string) error { - - //Construct key and tag to select the entry - key := ChainKey{ - Project: pr, - CompositeApp: ca, - CompositeAppVersion: caver, - NetControlIntent: netctrlint, - NetworkChain: name, - } - - err := db.DBconn.Remove(v.db.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete Chain Entry;") - } - - return nil -} diff --git a/src/ncm/pkg/module/module.go b/src/ncm/pkg/module/module.go index 21adaf9d..e3ebcccc 100644 --- a/src/ncm/pkg/module/module.go +++ b/src/ncm/pkg/module/module.go @@ -21,10 +21,6 @@ type Client struct { Cluster *ClusterClient Network *NetworkClient ProviderNet *ProviderNetClient - NetControlIntent *NetControlIntentClient - WorkloadIntent *WorkloadIntentClient - WorkloadIfIntent *WorkloadIfIntentClient - Chain *ChainClient // Add Clients for API's here } @@ -34,10 +30,6 @@ func NewClient() *Client { c.Cluster = NewClusterClient() c.Network = NewNetworkClient() c.ProviderNet = NewProviderNetClient() - c.NetControlIntent = NewNetControlIntentClient() - c.WorkloadIntent = NewWorkloadIntentClient() - c.WorkloadIfIntent = NewWorkloadIfIntentClient() - c.Chain = NewChainClient() // Add Client API handlers here return c } diff --git a/src/ncm/pkg/module/module_definitions.go b/src/ncm/pkg/module/module_definitions.go index 8d4b3ad7..efcbca95 100644 --- a/src/ncm/pkg/module/module_definitions.go +++ b/src/ncm/pkg/module/module_definitions.go @@ -31,9 +31,6 @@ const CNI_TYPE_OVN4NFV string = "ovn4nfv" var CNI_TYPES = [...]string{CNI_TYPE_OVN4NFV} -const YAML_START = "---\n" -const YAML_END = "...\n" - // It implements the interface for managing the ClusterProviders const MAX_DESCRIPTION_LEN int = 1024 const MAX_USERDATA_LEN int = 4096 diff --git a/src/ncm/pkg/module/netcontrolintent.go b/src/ncm/pkg/module/netcontrolintent.go deleted file mode 100644 index c005a935..00000000 --- a/src/ncm/pkg/module/netcontrolintent.go +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package module - -import ( - "encoding/json" - "strings" - - jyaml "github.com/ghodss/yaml" - - nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - - pkgerrors "github.com/pkg/errors" -) - -// NetControlIntent contains the parameters needed for dynamic networks -type NetControlIntent struct { - Metadata Metadata `json:"metadata"` -} - -// NetControlIntentKey is the key structure that is used in the database -type NetControlIntentKey struct { - NetControlIntent string `json:"netcontrolintent"` - Project string `json:"project"` - CompositeApp string `json:"compositeapp"` - CompositeAppVersion string `json:"compositeappversion"` -} - -// Manager is an interface exposing the NetControlIntent functionality -type NetControlIntentManager interface { - CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) - GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) - GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) - DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error - ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error -} - -// NetControlIntentClient implements the Manager -// It will also be used to maintain some localized state -type NetControlIntentClient struct { - db ClientDbInfo -} - -// NewNetControlIntentClient returns an instance of the NetControlIntentClient -// which implements the Manager -func NewNetControlIntentClient() *NetControlIntentClient { - return &NetControlIntentClient{ - db: ClientDbInfo{ - storeName: "orchestrator", - tagMeta: "netcontrolintentmetadata", - }, - } -} - -// CreateNetControlIntent - create a new NetControlIntent -func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) { - - //Construct key and tag to select the entry - key := NetControlIntentKey{ - NetControlIntent: nci.Metadata.Name, - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - } - - //Check if this NetControlIntent already exists - _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion) - if err == nil && !exists { - return NetControlIntent{}, pkgerrors.New("NetControlIntent already exists") - } - - err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, nci) - if err != nil { - return NetControlIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return nci, nil -} - -// GetNetControlIntent returns the NetControlIntent for corresponding name -func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) { - - //Construct key and tag to select the entry - key := NetControlIntentKey{ - NetControlIntent: name, - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - } - - value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntent") - } - - //value is a byte array - if value != nil { - nci := NetControlIntent{} - err = db.DBconn.Unmarshal(value[0], &nci) - if err != nil { - return NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - return nci, nil - } - - return NetControlIntent{}, pkgerrors.New("Error getting NetControlIntent") -} - -// GetNetControlIntentList returns all of the NetControlIntent for corresponding name -func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) { - - //Construct key and tag to select the entry - key := NetControlIntentKey{ - NetControlIntent: "", - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - } - - var resp []NetControlIntent - values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return []NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntents") - } - - for _, value := range values { - nci := NetControlIntent{} - err = db.DBconn.Unmarshal(value, &nci) - if err != nil { - return []NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - resp = append(resp, nci) - } - - return resp, nil -} - -// Delete the NetControlIntent from database -func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error { - - //Construct key and tag to select the entry - key := NetControlIntentKey{ - NetControlIntent: name, - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - } - - err := db.DBconn.Remove(v.db.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete NetControlIntent Entry;") - } - - return nil -} - -// (Test Routine) - Apply network-control-intent -func (v *NetControlIntentClient) ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error { - // TODO: Handle all Network Chain Intents for the Network Control Intent - - // Handle all Workload Intents for the Network Control Intent - wis, err := NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, name) - if err != nil { - return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", name, project, compositeapp, compositeappversion) - } - - // Setup the AppContext - var context appcontext.AppContext - _, err = context.LoadAppContext(appContextId) - if err != nil { - return pkgerrors.Wrapf(err, "Error getting AppContext with Id: %v for %v/%v%v", - appContextId, project, compositeapp, compositeappversion) - } - - // Handle all intents (currently just Interface intents) for each Workload Intent - for _, wi := range wis { - // The app/resource identified in the workload intent needs to be updated with two annotations. - // 1 - The "k8s.v1.cni.cncf.io/networks" annotation will have {"name": "ovn-networkobj", "namespace": "default"} added - // to it (preserving any existing values for this annotation. - // 2 - The "k8s.plugin.opnfv.org/nfn-network" annotation will add any network interfaces that are provided by the - // workload/interfaces intents. - - // Prepare the list of interfaces from the workload intent - wifs, err := NewWorkloadIfIntentClient().GetWorkloadIfIntents(project, - compositeapp, - compositeappversion, - name, - wi.Metadata.Name) - if err != nil { - return pkgerrors.Wrapf(err, - "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found", - wi.Metadata.Name, name, project, compositeapp, compositeappversion) - } - if len(wifs) == 0 { - log.Warn("No interface intents provided for workload intent", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": name, - "workload intent": wi.Metadata.Name, - }) - continue - } - - // Get all clusters for the current App from the AppContext - clusters, err := context.GetClusterNames(wi.Spec.AppName) - for _, c := range clusters { - rh, err := context.GetResourceHandle(wi.Spec.AppName, c, - strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+")) - if err != nil { - log.Warn("App Context resource handle not found", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": name, - "workload name": wi.Metadata.Name, - "app": wi.Spec.AppName, - "resource": wi.Spec.WorkloadResource, - "resource type": wi.Spec.Type, - }) - continue - } - r, err := context.GetValue(rh) - if err != nil { - log.Error("Error retrieving resource from App Context", log.Fields{ - "error": err, - "resource handle": rh, - }) - } - - // Unmarshal resource to K8S object - robj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string))) - - // Add network annotation to object - netAnnot := nettypes.NetworkSelectionElement{ - Name: "ovn-networkobj", - Namespace: "default", - } - AddNetworkAnnotation(robj, netAnnot) - - // Add nfn interface annotations to object - var newNfnIfs []WorkloadIfIntentSpec - for _, i := range wifs { - newNfnIfs = append(newNfnIfs, i.Spec) - } - AddNfnAnnotation(robj, newNfnIfs) - - // Marshal object back to yaml format (via json - seems to eliminate most clutter) - j, err := json.Marshal(robj) - if err != nil { - log.Error("Error marshalling resource to JSON", log.Fields{ - "error": err, - }) - continue - } - y, err := jyaml.JSONToYAML(j) - if err != nil { - log.Error("Error marshalling resource to YAML", log.Fields{ - "error": err, - }) - continue - } - - // Update resource in AppContext - err = context.UpdateResourceValue(rh, string(y)) - if err != nil { - log.Error("Network updating app context resource handle", log.Fields{ - "error": err, - "resource handle": rh, - }) - } - } - } - - return nil -} diff --git a/src/ncm/pkg/module/resources.go b/src/ncm/pkg/module/resources.go deleted file mode 100644 index 24c9833e..00000000 --- a/src/ncm/pkg/module/resources.go +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package module - -import ( - "encoding/json" - "fmt" - - nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" - netutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils" - log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" - v1 "k8s.io/api/apps/v1" - batch "k8s.io/api/batch/v1" - batchv1beta1 "k8s.io/api/batch/v1beta1" - v1core "k8s.io/api/core/v1" - _ "k8s.io/kubernetes/pkg/apis/apps/install" - _ "k8s.io/kubernetes/pkg/apis/batch/install" - _ "k8s.io/kubernetes/pkg/apis/core/install" - _ "k8s.io/kubernetes/pkg/apis/extensions/install" - - pkgerrors "github.com/pkg/errors" -) - -type NfnAnnotation struct { - CniType string - Interface []WorkloadIfIntentSpec -} - -const NfnAnnotationKey = "k8s.plugin.opnfv.org/nfn-network" - -// ParsePodTemplateNetworkAnnotation parses Pod annotation in PodTemplate -func ParsePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec) ([]*nettypes.NetworkSelectionElement, error) { - netAnnot := pt.Annotations[nettypes.NetworkAttachmentAnnot] - defaultNamespace := pt.Namespace - - if len(netAnnot) == 0 { - return nil, pkgerrors.Errorf("No kubernetes network annotation found") - } - - networks, err := netutils.ParseNetworkAnnotation(netAnnot, defaultNamespace) - if err != nil { - return nil, err - } - return networks, nil -} - -// GetPodTemplateNetworkAnnotation gets Pod Nfn annotation in PodTemplate -func GetPodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec) NfnAnnotation { - var nfn NfnAnnotation - - nfnAnnot := pt.Annotations[NfnAnnotationKey] - if len(nfnAnnot) == 0 { - return nfn - } - - err := json.Unmarshal([]byte(nfnAnnot), &nfn) - if err != nil { - log.Warn("Error unmarshalling nfn annotation", log.Fields{ - "annotation": nfnAnnot, - }) - } - return nfn -} - -// GetPodNetworkAnnotation gets Pod Nfn annotation in PodTemplate -func GetPodNfnAnnotation(p *v1core.Pod) NfnAnnotation { - var nfn NfnAnnotation - - nfnAnnot := p.Annotations[NfnAnnotationKey] - if len(nfnAnnot) == 0 { - return nfn - } - - err := json.Unmarshal([]byte(nfnAnnot), &nfn) - if err != nil { - log.Warn("Error unmarshalling nfn annotation", log.Fields{ - "annotation": nfnAnnot, - }) - } - return nfn -} - -func addNetworkAnnotation(a nettypes.NetworkSelectionElement, as []*nettypes.NetworkSelectionElement) []*nettypes.NetworkSelectionElement { - var netElements []*nettypes.NetworkSelectionElement - - found := false - for _, e := range as { - if e.Name == a.Name { - found = true - } - netElements = append(netElements, e) - } - if !found { - netElements = append(netElements, &a) - } - - return netElements -} - -// Add the interfaces in the 'new' parameter to the nfn annotation -func newNfnIfs(nfn NfnAnnotation, new []WorkloadIfIntentSpec) NfnAnnotation { - // Prepare a new interface list - combining the original plus new ones - var newNfn NfnAnnotation - - if nfn.CniType != CNI_TYPE_OVN4NFV { - if len(nfn.CniType) > 0 { - log.Warn("Error existing nfn cnitype is invalid", log.Fields{ - "existing cnitype": nfn.CniType, - "using cnitype": CNI_TYPE_OVN4NFV, - }) - } - } - newNfn.CniType = CNI_TYPE_OVN4NFV - - // update any interfaces already in the list with the updated interface - for _, i := range nfn.Interface { - for _, j := range new { - if i.NetworkName == j.NetworkName && i.IfName == j.IfName { - i.DefaultGateway = j.DefaultGateway - i.IpAddr = j.IpAddr - i.MacAddr = j.MacAddr - break - } - } - newNfn.Interface = append(newNfn.Interface, i) - } - - // add new interfaces not present in original list - for _, j := range new { - found := false - for _, i := range nfn.Interface { - if i.NetworkName == j.NetworkName && i.IfName == j.IfName { - found = true - break - } - } - if !found { - newNfn.Interface = append(newNfn.Interface, j) - } - } - return newNfn -} - -func updatePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec, a nettypes.NetworkSelectionElement) { - netAnnotation, _ := ParsePodTemplateNetworkAnnotation(pt) - elements := addNetworkAnnotation(a, netAnnotation) - j, err := json.Marshal(elements) - if err != nil { - log.Error("Existing network annotation has invalid format", log.Fields{ - "error": err, - }) - return - } - if pt.Annotations == nil { - pt.Annotations = make(map[string]string) - } - pt.Annotations[nettypes.NetworkAttachmentAnnot] = string(j) -} - -// Add a network annotation to the resource -func AddNetworkAnnotation(r interface{}, a nettypes.NetworkSelectionElement) { - - switch o := r.(type) { - case *batch.Job: - updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) - case *batchv1beta1.CronJob: - updatePodTemplateNetworkAnnotation(&o.Spec.JobTemplate.Spec.Template, a) - case *v1.DaemonSet: - updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) - case *v1.Deployment: - updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) - case *v1.ReplicaSet: - updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) - case *v1.StatefulSet: - updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) - case *v1core.Pod: - netAnnotation, _ := netutils.ParsePodNetworkAnnotation(o) - elements := addNetworkAnnotation(a, netAnnotation) - j, err := json.Marshal(elements) - if err != nil { - log.Error("Existing network annotation has invalid format", log.Fields{ - "error": err, - }) - break - } - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - o.Annotations[nettypes.NetworkAttachmentAnnot] = string(j) - return - case *v1core.ReplicationController: - updatePodTemplateNetworkAnnotation(o.Spec.Template, a) - default: - typeStr := fmt.Sprintf("%T", o) - log.Warn("Network annotations not supported for resource type", log.Fields{ - "resource type": typeStr, - }) - } -} - -func updatePodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec, new []WorkloadIfIntentSpec) { - nfnAnnotation := GetPodTemplateNfnAnnotation(pt) - newNfnAnnotation := newNfnIfs(nfnAnnotation, new) - j, err := json.Marshal(newNfnAnnotation) - if err != nil { - log.Error("Network nfn annotation has invalid format", log.Fields{ - "error": err, - }) - return - } - if pt.Annotations == nil { - pt.Annotations = make(map[string]string) - } - pt.Annotations[NfnAnnotationKey] = string(j) -} - -// Add an nfn annotation to the resource -func AddNfnAnnotation(r interface{}, new []WorkloadIfIntentSpec) { - - switch o := r.(type) { - case *batch.Job: - updatePodTemplateNfnAnnotation(&o.Spec.Template, new) - case *batchv1beta1.CronJob: - updatePodTemplateNfnAnnotation(&o.Spec.JobTemplate.Spec.Template, new) - case *v1.DaemonSet: - updatePodTemplateNfnAnnotation(&o.Spec.Template, new) - return - case *v1.Deployment: - updatePodTemplateNfnAnnotation(&o.Spec.Template, new) - return - case *v1.ReplicaSet: - updatePodTemplateNfnAnnotation(&o.Spec.Template, new) - case *v1.StatefulSet: - updatePodTemplateNfnAnnotation(&o.Spec.Template, new) - case *v1core.Pod: - nfnAnnotation := GetPodNfnAnnotation(o) - newNfnAnnotation := newNfnIfs(nfnAnnotation, new) - j, err := json.Marshal(newNfnAnnotation) - if err != nil { - log.Error("Network nfn annotation has invalid format", log.Fields{ - "error": err, - }) - break - } - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - o.Annotations[NfnAnnotationKey] = string(j) - return - case *v1core.ReplicationController: - updatePodTemplateNfnAnnotation(o.Spec.Template, new) - return - default: - typeStr := fmt.Sprintf("%T", o) - log.Warn("Network nfn annotations not supported for resource type", log.Fields{ - "resource type": typeStr, - }) - } -} diff --git a/src/ncm/pkg/module/workloadifintent.go b/src/ncm/pkg/module/workloadifintent.go deleted file mode 100644 index 55062564..00000000 --- a/src/ncm/pkg/module/workloadifintent.go +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package module - -import ( - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - - pkgerrors "github.com/pkg/errors" -) - -// WorkloadIfIntent contains the parameters needed for dynamic networks -type WorkloadIfIntent struct { - Metadata Metadata `json:"metadata"` - Spec WorkloadIfIntentSpec `json:"spec"` -} - -type WorkloadIfIntentSpec struct { - IfName string `json:"interface"` - NetworkName string `json:"name"` - DefaultGateway string `json:"defaultGateway"` // optional, default value is "false" - IpAddr string `json:"ipAddress,omitempty"` // optional, if not provided then will be dynamically allocated - MacAddr string `json:"macAddress,omitempty"` // optional, if not provided then will be dynamically allocated -} - -// WorkloadIfIntentKey is the key structure that is used in the database -type WorkloadIfIntentKey struct { - Project string `json:"provider"` - CompositeApp string `json:"compositeapp"` - CompositeAppVersion string `json:"compositeappversion"` - NetControlIntent string `json:"netcontrolintent"` - WorkloadIntent string `json:"workloadintent"` - WorkloadIfIntent string `json:"workloadifintent"` -} - -// Manager is an interface exposing the WorkloadIfIntent functionality -type WorkloadIfIntentManager interface { - CreateWorkloadIfIntent(wi WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) - GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) - GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) - DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error -} - -// WorkloadIfIntentClient implements the Manager -// It will also be used to maintain some localized state -type WorkloadIfIntentClient struct { - db ClientDbInfo -} - -// NewWorkloadIfIntentClient returns an instance of the WorkloadIfIntentClient -// which implements the Manager -func NewWorkloadIfIntentClient() *WorkloadIfIntentClient { - return &WorkloadIfIntentClient{ - db: ClientDbInfo{ - storeName: "orchestrator", - tagMeta: "workloadifintentmetadata", - }, - } -} - -// CreateWorkloadIfIntent - create a new WorkloadIfIntent -func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIfIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: workloadintent, - WorkloadIfIntent: wif.Metadata.Name, - } - - //Check if the Workload Intent exists - _, err := NewWorkloadIntentClient().GetWorkloadIntent(workloadintent, project, compositeapp, compositeappversion, netcontrolintent) - if err != nil { - return WorkloadIfIntent{}, pkgerrors.Errorf("Workload Intent %v does not exist", workloadintent) - } - - //Check if this WorkloadIfIntent already exists - _, err = v.GetWorkloadIfIntent(wif.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent) - if err == nil && !exists { - return WorkloadIfIntent{}, pkgerrors.New("WorkloadIfIntent already exists") - } - - err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wif) - if err != nil { - return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return wif, nil -} - -// GetWorkloadIfIntent returns the WorkloadIfIntent for corresponding name -func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIfIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: workloadintent, - WorkloadIfIntent: name, - } - - value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntent") - } - - //value is a byte array - if value != nil { - wif := WorkloadIfIntent{} - err = db.DBconn.Unmarshal(value[0], &wif) - if err != nil { - return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - return wif, nil - } - - return WorkloadIfIntent{}, pkgerrors.New("Error getting WorkloadIfIntent") -} - -// GetWorkloadIfIntentList returns all of the WorkloadIfIntent for corresponding name -func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIfIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: workloadintent, - WorkloadIfIntent: "", - } - - var resp []WorkloadIfIntent - values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntents") - } - - for _, value := range values { - wif := WorkloadIfIntent{} - err = db.DBconn.Unmarshal(value, &wif) - if err != nil { - return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - resp = append(resp, wif) - } - - return resp, nil -} - -// Delete the WorkloadIfIntent from database -func (v *WorkloadIfIntentClient) DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error { - - //Construct key and tag to select the entry - key := WorkloadIfIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: workloadintent, - WorkloadIfIntent: name, - } - - err := db.DBconn.Remove(v.db.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete WorkloadIfIntent Entry;") - } - - return nil -} diff --git a/src/ncm/pkg/module/workloadintent.go b/src/ncm/pkg/module/workloadintent.go deleted file mode 100644 index e6916954..00000000 --- a/src/ncm/pkg/module/workloadintent.go +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2020 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package module - -import ( - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - - pkgerrors "github.com/pkg/errors" -) - -// WorkloadIntent contains the parameters needed for dynamic networks -type WorkloadIntent struct { - Metadata Metadata `json:"metadata"` - Spec WorkloadIntentSpec `json:"spec"` -} - -type WorkloadIntentSpec struct { - AppName string `json:"application-name"` - WorkloadResource string `json:"workload-resource"` - Type string `json:"type"` -} - -// WorkloadIntentKey is the key structure that is used in the database -type WorkloadIntentKey struct { - Project string `json:"provider"` - CompositeApp string `json:"compositeapp"` - CompositeAppVersion string `json:"compositeappversion"` - NetControlIntent string `json:"netcontrolintent"` - WorkloadIntent string `json:"workloadintent"` -} - -// Manager is an interface exposing the WorkloadIntent functionality -type WorkloadIntentManager interface { - CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) - GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) - GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) - DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error -} - -// WorkloadIntentClient implements the Manager -// It will also be used to maintain some localized state -type WorkloadIntentClient struct { - db ClientDbInfo -} - -// NewWorkloadIntentClient returns an instance of the WorkloadIntentClient -// which implements the Manager -func NewWorkloadIntentClient() *WorkloadIntentClient { - return &WorkloadIntentClient{ - db: ClientDbInfo{ - storeName: "orchestrator", - tagMeta: "workloadintentmetadata", - }, - } -} - -// CreateWorkloadIntent - create a new WorkloadIntent -func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: wi.Metadata.Name, - } - - //Check if the Network Control Intent exists - _, err := NewNetControlIntentClient().GetNetControlIntent(netcontrolintent, project, compositeapp, compositeappversion) - if err != nil { - return WorkloadIntent{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netcontrolintent) - } - - //Check if this WorkloadIntent already exists - _, err = v.GetWorkloadIntent(wi.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent) - if err == nil && !exists { - return WorkloadIntent{}, pkgerrors.New("WorkloadIntent already exists") - } - - err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wi) - if err != nil { - return WorkloadIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return wi, nil -} - -// GetWorkloadIntent returns the WorkloadIntent for corresponding name -func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: name, - } - - value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntent") - } - - //value is a byte array - if value != nil { - wi := WorkloadIntent{} - err = db.DBconn.Unmarshal(value[0], &wi) - if err != nil { - return WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - return wi, nil - } - - return WorkloadIntent{}, pkgerrors.New("Error getting WorkloadIntent") -} - -// GetWorkloadIntentList returns all of the WorkloadIntent for corresponding name -func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) { - - //Construct key and tag to select the entry - key := WorkloadIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: "", - } - - var resp []WorkloadIntent - values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) - if err != nil { - return []WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntents") - } - - for _, value := range values { - wi := WorkloadIntent{} - err = db.DBconn.Unmarshal(value, &wi) - if err != nil { - return []WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") - } - resp = append(resp, wi) - } - - return resp, nil -} - -// Delete the WorkloadIntent from database -func (v *WorkloadIntentClient) DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error { - - //Construct key and tag to select the entry - key := WorkloadIntentKey{ - Project: project, - CompositeApp: compositeapp, - CompositeAppVersion: compositeappversion, - NetControlIntent: netcontrolintent, - WorkloadIntent: name, - } - - err := db.DBconn.Remove(v.db.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete WorkloadIntent Entry;") - } - - return nil -} diff --git a/src/orchestrator/go.sum b/src/orchestrator/go.sum index e66e73cd..804638be 100644 --- a/src/orchestrator/go.sum +++ b/src/orchestrator/go.sum @@ -274,6 +274,8 @@ github.com/onap/multicloud-k8s/src/k8splugin v0.0.0-20191115005109-f168ebb73d8d/ github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee h1:/PdsvtVvzmDdeQBswNrJlVEi3Q86p/jOv3z6XMi8Nu4= github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee/go.mod h1:q6s8c45A2NN2V4lxciJ7OmCZFaS1uQSWaGxGG3UM3kM= github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200527175204-ef27eb4d63f1/go.mod h1:zpEOrSrzSCEO2dqjW5nullfXbjs9UQOTiJdJxUCwirI= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200529003854-0a7bf256bde5 h1:ADsdcBpxbFNQsRymp+zPywQWBscybnFTp+gVVPmA7ps= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200529003854-0a7bf256bde5/go.mod h1:KdaZWMi5L33rQyuAtwMmtsgUv/TuG0iskqckToeb58g= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= diff --git a/src/ovnaction/Makefile b/src/ovnaction/Makefile new file mode 100644 index 00000000..4ab6246b --- /dev/null +++ b/src/ovnaction/Makefile @@ -0,0 +1,36 @@ +# SPDX-license-identifier: Apache-2.0 +############################################################################## +# Copyright (c) 2020 Intel Corporation +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +export GO111MODULE=on + +all: clean + CGO_ENABLED=1 GOOS=linux GOARCH=amd64 + @go build -tags netgo -o ./ovnaction ./cmd/main.go + +# The following is done this way as each patch on CI runs build and each merge runs deploy. So for build we don't need to build binary and hence +# no need to create a static binary with additional flags. However, for generating binary, additional build flags are necessary. This if used with +# mock plugin errors out for unit tests. So the seperation avoids the error. + +build: clean test cover +deploy: build + +.PHONY: test +test: clean + @go test -race ./... + +format: + @go fmt ./... + +clean: + @rm -f ovnaction coverage.html coverage.out + +.PHONY: cover +cover: + @go test -race ./... -coverprofile=coverage.out + @go tool cover -html=coverage.out -o coverage.html diff --git a/src/ovnaction/api/api.go b/src/ovnaction/api/api.go new file mode 100644 index 00000000..bffab0a4 --- /dev/null +++ b/src/ovnaction/api/api.go @@ -0,0 +1,113 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package api + +import ( + "fmt" + "reflect" + + "github.com/gorilla/mux" + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" +) + +var moduleClient *moduleLib.Client + +// For the given client and testClient, if the testClient is not null and +// implements the client manager interface corresponding to client, then +// return the testClient, otherwise return the client. +func setClient(client, testClient interface{}) interface{} { + switch cl := client.(type) { + case *moduleLib.NetControlIntentClient: + if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.NetControlIntentManager)(nil)).Elem()) { + c, ok := testClient.(moduleLib.NetControlIntentManager) + if ok { + return c + } + } + case *moduleLib.WorkloadIntentClient: + if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.WorkloadIntentManager)(nil)).Elem()) { + c, ok := testClient.(moduleLib.WorkloadIntentManager) + if ok { + return c + } + } + case *moduleLib.WorkloadIfIntentClient: + if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.WorkloadIfIntentManager)(nil)).Elem()) { + c, ok := testClient.(moduleLib.WorkloadIfIntentManager) + if ok { + return c + } + } + case *moduleLib.ChainClient: + if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.ChainManager)(nil)).Elem()) { + c, ok := testClient.(moduleLib.ChainManager) + if ok { + return c + } + } + default: + fmt.Printf("unknown type %T\n", cl) + } + return client +} + +// NewRouter creates a router that registers the various urls that are supported +// testClient parameter allows unit testing for a given client +func NewRouter(testClient interface{}) *mux.Router { + + moduleClient = moduleLib.NewClient() + + router := mux.NewRouter().PathPrefix("/v2").Subrouter() + + netcontrolintentHandler := netcontrolintentHandler{ + client: setClient(moduleClient.NetControlIntent, testClient).(moduleLib.NetControlIntentManager), + } + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.deleteHandler).Methods("DELETE") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}/apply", netcontrolintentHandler.applyHandler).Methods("POST") + + workloadintentHandler := workloadintentHandler{ + client: setClient(moduleClient.WorkloadIntent, testClient).(moduleLib.WorkloadIntentManager), + } + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.deleteHandler).Methods("DELETE") + + workloadifintentHandler := workloadifintentHandler{ + client: setClient(moduleClient.WorkloadIfIntent, testClient).(moduleLib.WorkloadIfIntentManager), + } + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.deleteHandler).Methods("DELETE") + + chainHandler := chainHandler{ + client: setClient(moduleClient.Chain, testClient).(moduleLib.ChainManager), + } + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.deleteHandler).Methods("DELETE") + + return router +} diff --git a/src/ovnaction/api/chainhandler.go b/src/ovnaction/api/chainhandler.go new file mode 100644 index 00000000..52ed18e5 --- /dev/null +++ b/src/ovnaction/api/chainhandler.go @@ -0,0 +1,290 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package api + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + pkgerrors "github.com/pkg/errors" + + "github.com/gorilla/mux" +) + +// Used to store backend implementations objects +// Also simplifies mocking for unit testing purposes +type chainHandler struct { + // Interface that implements workload intent operations + // We will set this variable with a mock interface for testing + client moduleLib.ChainManager +} + +func validateRoutingNetwork(r moduleLib.RoutingNetwork) error { + errs := validation.IsValidName(r.NetworkName) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid routing network name: %v", errs) + } + + err := validation.IsIpv4Cidr(r.Subnet) + if err != nil { + return pkgerrors.Wrap(err, "Invalid routing network subnet") + } + + err = validation.IsIpv4(r.GatewayIP) + if err != nil { + return pkgerrors.Wrap(err, "Invalid routing network gateway IP") + } + + return nil +} + +// validateNetworkChain checks that the network chain string input follows the +// generic format: "app=app1,net1,app=app2,net2, ..... ,netN-1,app=appN" +// assume "app=app1" can conform to validation.IsValidLabel() with an "=" +func validateNetworkChain(chain string) error { + elems := strings.Split(chain, ",") + + // chain needs at least two apps and a network + if len(elems) < 3 { + return pkgerrors.Errorf("Network chain is too short") + } + + // chain needs to have an odd number of elements + if len(elems)%2 == 0 { + return pkgerrors.Errorf("Invalid network chain - even number of elements") + } + + for i, s := range elems { + // allows whitespace in comma separated elements + t := strings.TrimSpace(s) + // if even element, verify a=b format + if i%2 == 0 { + if strings.Index(t, "=") < 1 { + return pkgerrors.Errorf("Invalid deployment label element of network chain") + } + errs := validation.IsValidLabel(t) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid deployment label element: %v", errs) + } + } else { + errs := validation.IsValidName(t) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid network element of network chain: %v", errs) + } + } + } + return nil +} + +// Check for valid format of input parameters +func validateChainInputs(ch moduleLib.Chain) error { + // validate metadata + err := moduleLib.IsValidMetadata(ch.Metadata) + if err != nil { + return pkgerrors.Wrap(err, "Invalid network chain metadata") + } + + if strings.ToLower(ch.Spec.ChainType) != moduleLib.RoutingChainType { + return pkgerrors.Wrap(err, "Invalid network chain type") + } + + for _, r := range ch.Spec.RoutingSpec.LeftNetwork { + err = validateRoutingNetwork(r) + if err != nil { + return err + } + } + + for _, r := range ch.Spec.RoutingSpec.RightNetwork { + err = validateRoutingNetwork(r) + if err != nil { + return err + } + } + + err = validateNetworkChain(ch.Spec.RoutingSpec.NetworkChain) + if err != nil { + return err + } + + errs := validation.IsValidName(ch.Spec.RoutingSpec.Namespace) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid network chain route spec namespace: %v", errs) + } + + return nil +} + +// Create handles creation of the Chain entry in the database +func (h chainHandler) createHandler(w http.ResponseWriter, r *http.Request) { + var ch moduleLib.Chain + vars := mux.Vars(r) + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := json.NewDecoder(r.Body).Decode(&ch) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if ch.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + err = validateChainInputs(ch) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, false) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Put handles creation/update of the Chain entry in the database +func (h chainHandler) putHandler(w http.ResponseWriter, r *http.Request) { + var ch moduleLib.Chain + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := json.NewDecoder(r.Body).Decode(&ch) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if ch.Metadata.Name == "" { + http.Error(w, "Missing name in PUT request", http.StatusBadRequest) + return + } + + // Name in URL should match name in body + if ch.Metadata.Name != name { + fmt.Printf("bodyname = %v, name= %v\n", ch.Metadata.Name, name) + http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) + return + } + + err = validateChainInputs(ch) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, true) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Get handles GET operations on a particular Chain Name +// Returns a Chain +func (h chainHandler) getHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + var ret interface{} + var err error + + if len(name) == 0 { + ret, err = h.client.GetChains(project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetChain(name, project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Delete handles DELETE operations on a particular Chain +func (h chainHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := h.client.DeleteChain(name, project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/src/ovnaction/api/chainhandler_test.go b/src/ovnaction/api/chainhandler_test.go new file mode 100644 index 00000000..f13a90c4 --- /dev/null +++ b/src/ovnaction/api/chainhandler_test.go @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package api + +import ( + "testing" +) + +func TestIsValidNetworkChain(t *testing.T) { + t.Run("Valid Chains", func(t *testing.T) { + validchains := []string{ + "app=abc,net1,app=xyz", + "app=abc, net1, app=xyz", + " app=abc , net1 , app=xyz ", + "app.kubernets.io/name=abc,net1,app.kubernets.io/name=xyz", + "app.kubernets.io/name=abc,net1,app.kubernets.io/name=xyz, net2, anotherlabel=wex", + } + for _, chain := range validchains { + err := validateNetworkChain(chain) + if err != nil { + t.Errorf("Valid network chain failed to pass: %v %v", chain, err) + } + } + }) + + t.Run("Invalid Chains", func(t *testing.T) { + invalidchains := []string{ + "", + "app=abc,net1,app= xyz", + "app=abc,net1,xyz", + "app=abc,net1", + "app.kubernets.io/name=abc,net1,=xyz", + "abcdefg", + } + for _, chain := range invalidchains { + err := validateNetworkChain(chain) + if err == nil { + t.Errorf("Invalid network chain passed: %v", chain) + } + } + }) +} diff --git a/src/ovnaction/api/netcontrolintenthandler.go b/src/ovnaction/api/netcontrolintenthandler.go new file mode 100644 index 00000000..fe2109b6 --- /dev/null +++ b/src/ovnaction/api/netcontrolintenthandler.go @@ -0,0 +1,232 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package api + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" + pkgerrors "github.com/pkg/errors" + + "github.com/gorilla/mux" +) + +// Used to store backend implementations objects +// Also simplifies mocking for unit testing purposes +type netcontrolintentHandler struct { + // Interface that implements Cluster operations + // We will set this variable with a mock interface for testing + client moduleLib.NetControlIntentManager +} + +// Check for valid format of input parameters +func validateNetControlIntentInputs(nci moduleLib.NetControlIntent) error { + // validate metadata + err := moduleLib.IsValidMetadata(nci.Metadata) + if err != nil { + return pkgerrors.Wrap(err, "Invalid network controller intent metadata") + } + return nil +} + +// Create handles creation of the NetControlIntent entry in the database +func (h netcontrolintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { + var nci moduleLib.NetControlIntent + vars := mux.Vars(r) + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + + err := json.NewDecoder(r.Body).Decode(&nci) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if nci.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + err = validateNetControlIntentInputs(nci) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, false) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Put handles creation/update of the NetControlIntent entry in the database +func (h netcontrolintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { + var nci moduleLib.NetControlIntent + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + + err := json.NewDecoder(r.Body).Decode(&nci) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if nci.Metadata.Name == "" { + http.Error(w, "Missing name in PUT request", http.StatusBadRequest) + return + } + + // Name in URL should match name in body + if nci.Metadata.Name != name { + fmt.Printf("bodyname = %v, name= %v\n", nci.Metadata.Name, name) + http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) + return + } + + err = validateNetControlIntentInputs(nci) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, true) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Get handles GET operations on a particular NetControlIntent Name +// Returns a NetControlIntent +func (h netcontrolintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + var ret interface{} + var err error + + if len(name) == 0 { + ret, err = h.client.GetNetControlIntents(project, compositeApp, compositeAppVersion) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetNetControlIntent(name, project, compositeApp, compositeAppVersion) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Delete handles DELETE operations on a particular NetControlIntent Name +func (h netcontrolintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + + err := h.client.DeleteNetControlIntent(name, project, compositeApp, compositeAppVersion) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// Apply handles POST operations to Apply a particular NetControlIntent to the App Context +// TODO: This is a test API - it can be removed once the orchestrator has been implemented to +// invoke the appcontext update via grpc. +func (h netcontrolintentHandler) applyHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + + var aci struct { + AppContextId string `json:"appContextId"` + } + + err := json.NewDecoder(r.Body).Decode(&aci) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + err = h.client.ApplyNetControlIntent(name, project, compositeApp, compositeAppVersion, aci.AppContextId) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/src/ovnaction/api/workloadifintenthandler.go b/src/ovnaction/api/workloadifintenthandler.go new file mode 100644 index 00000000..cf8f45bf --- /dev/null +++ b/src/ovnaction/api/workloadifintenthandler.go @@ -0,0 +1,251 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package api + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + pkgerrors "github.com/pkg/errors" + + "github.com/gorilla/mux" +) + +// Used to store backend implementations objects +// Also simplifies mocking for unit testing purposes +type workloadifintentHandler struct { + // Interface that implements workload intent operations + // We will set this variable with a mock interface for testing + client moduleLib.WorkloadIfIntentManager +} + +// Check for valid format of input parameters +func validateWorkloadIfIntentInputs(wif moduleLib.WorkloadIfIntent) error { + // validate metadata + err := moduleLib.IsValidMetadata(wif.Metadata) + if err != nil { + return pkgerrors.Wrap(err, "Invalid network controller intent metadata") + } + + errs := validation.IsValidName(wif.Spec.IfName) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid interface name = [%v], errors: %v", wif.Spec.IfName, errs) + } + + errs = validation.IsValidName(wif.Spec.NetworkName) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid network name = [%v], errors: %v", wif.Spec.NetworkName, errs) + } + + // optional - only validate if supplied + if len(wif.Spec.DefaultGateway) > 0 { + errs = validation.IsValidName(wif.Spec.DefaultGateway) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid default interface = [%v], errors: %v", wif.Spec.DefaultGateway, errs) + } + } + + // optional - only validate if supplied + if len(wif.Spec.IpAddr) > 0 { + err = validation.IsIp(wif.Spec.IpAddr) + if err != nil { + return pkgerrors.Errorf("Invalid IP address = [%v], errors: %v", wif.Spec.IpAddr, err) + } + } + + // optional - only validate if supplied + if len(wif.Spec.MacAddr) > 0 { + err = validation.IsMac(wif.Spec.MacAddr) + if err != nil { + return pkgerrors.Errorf("Invalid MAC address = [%v], errors: %v", wif.Spec.MacAddr, err) + } + } + return nil +} + +// Create handles creation of the Network entry in the database +func (h workloadifintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { + var wif moduleLib.WorkloadIfIntent + vars := mux.Vars(r) + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + workloadIntent := vars["workload-intent"] + + err := json.NewDecoder(r.Body).Decode(&wif) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if wif.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + // set default value + if len(wif.Spec.DefaultGateway) == 0 { + wif.Spec.DefaultGateway = "false" // set default value + } + + err = validateWorkloadIfIntentInputs(wif) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, false) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Put handles creation/update of the Network entry in the database +func (h workloadifintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { + var wif moduleLib.WorkloadIfIntent + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + workloadIntent := vars["workload-intent"] + + err := json.NewDecoder(r.Body).Decode(&wif) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if wif.Metadata.Name == "" { + http.Error(w, "Missing name in PUT request", http.StatusBadRequest) + return + } + + // Name in URL should match name in body + if wif.Metadata.Name != name { + fmt.Printf("bodyname = %v, name= %v\n", wif.Metadata.Name, name) + http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) + return + } + + // set default value + if len(wif.Spec.DefaultGateway) == 0 { + wif.Spec.DefaultGateway = "false" // set default value + } + + err = validateWorkloadIfIntentInputs(wif) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, true) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Get handles GET operations on a particular Network Name +// Returns a Network +func (h workloadifintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + workloadIntent := vars["workload-intent"] + var ret interface{} + var err error + + if len(name) == 0 { + ret, err = h.client.GetWorkloadIfIntents(project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Delete handles DELETE operations on a particular Network Name +func (h workloadifintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + workloadIntent := vars["workload-intent"] + + err := h.client.DeleteWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/src/ovnaction/api/workloadintenthandler.go b/src/ovnaction/api/workloadintenthandler.go new file mode 100644 index 00000000..cf7ecebc --- /dev/null +++ b/src/ovnaction/api/workloadintenthandler.go @@ -0,0 +1,218 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package api + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + pkgerrors "github.com/pkg/errors" + + "github.com/gorilla/mux" +) + +// Used to store backend implementations objects +// Also simplifies mocking for unit testing purposes +type workloadintentHandler struct { + // Interface that implements workload intent operations + // We will set this variable with a mock interface for testing + client moduleLib.WorkloadIntentManager +} + +// Check for valid format of input parameters +func validateWorkloadIntentInputs(wi moduleLib.WorkloadIntent) error { + // validate metadata + err := moduleLib.IsValidMetadata(wi.Metadata) + if err != nil { + return pkgerrors.Wrap(err, "Invalid network controller intent metadata") + } + + errs := validation.IsValidName(wi.Spec.AppName) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid application name = [%v], errors: %v", wi.Spec.AppName, errs) + } + + errs = validation.IsValidName(wi.Spec.WorkloadResource) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid workload resource = [%v], errors: %v", wi.Spec.WorkloadResource, errs) + } + + errs = validation.IsValidName(wi.Spec.Type) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid workload type = [%v], errors: %v", wi.Spec.Type, errs) + } + return nil +} + +// Create handles creation of the Network entry in the database +func (h workloadintentHandler) createHandler(w http.ResponseWriter, r *http.Request) { + var wi moduleLib.WorkloadIntent + vars := mux.Vars(r) + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := json.NewDecoder(r.Body).Decode(&wi) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if wi.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + err = validateWorkloadIntentInputs(wi) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, false) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Put handles creation/update of the Network entry in the database +func (h workloadintentHandler) putHandler(w http.ResponseWriter, r *http.Request) { + var wi moduleLib.WorkloadIntent + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := json.NewDecoder(r.Body).Decode(&wi) + + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if wi.Metadata.Name == "" { + http.Error(w, "Missing name in PUT request", http.StatusBadRequest) + return + } + + // Name in URL should match name in body + if wi.Metadata.Name != name { + fmt.Printf("bodyname = %v, name= %v\n", wi.Metadata.Name, name) + http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) + return + } + + err = validateWorkloadIntentInputs(wi) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, true) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Get handles GET operations on a particular Network Name +// Returns a Network +func (h workloadintentHandler) getHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + var ret interface{} + var err error + + if len(name) == 0 { + ret, err = h.client.GetWorkloadIntents(project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// Delete handles DELETE operations on a particular Network Name +func (h workloadintentHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + project := vars["project"] + compositeApp := vars["composite-app-name"] + compositeAppVersion := vars["version"] + netControlIntent := vars["net-control-intent"] + + err := h.client.DeleteWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/src/ovnaction/cmd/main.go b/src/ovnaction/cmd/main.go new file mode 100644 index 00000000..1f33af25 --- /dev/null +++ b/src/ovnaction/cmd/main.go @@ -0,0 +1,134 @@ +/* +Copyright 2020 Intel Corporation. +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 main + +import ( + "context" + "fmt" + "log" + "math/rand" + "net" + "net/http" + "os" + "os/signal" + "strings" + "time" + + "github.com/gorilla/handlers" + "github.com/onap/multicloud-k8s/src/ncm/pkg/grpc/contextupdateserver" + updatepb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/contextupdate" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/auth" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/config" + contextDb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/contextdb" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + "github.com/onap/multicloud-k8s/src/ovnaction/api" + register "github.com/onap/multicloud-k8s/src/ovnaction/pkg/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/testdata" +) + +func startGrpcServer() error { + var tls bool + + if strings.Contains(config.GetConfiguration().GrpcEnableTLS, "enable") { + tls = true + } else { + tls = false + } + certFile := config.GetConfiguration().GrpcServerCert + keyFile := config.GetConfiguration().GrpcServerKey + + host, port := register.GetServerHostPort() + + lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) + if err != nil { + log.Fatalf("Could not listen to port: %v", err) + } + var opts []grpc.ServerOption + if tls { + if certFile == "" { + certFile = testdata.Path("server.pem") + } + if keyFile == "" { + keyFile = testdata.Path("server.key") + } + creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) + if err != nil { + log.Fatalf("Could not generate credentials %v", err) + } + opts = []grpc.ServerOption{grpc.Creds(creds)} + } + grpcServer := grpc.NewServer(opts...) + updatepb.RegisterContextupdateServer(grpcServer, contextupdateserver.NewContextupdateServer()) + + log.Println("Starting Network Configuration Manager gRPC Server") + err = grpcServer.Serve(lis) + if err != nil { + log.Fatalf("ncm grpc server is not serving %v", err) + } + return err +} + +func main() { + rand.Seed(time.Now().UnixNano()) + + err := db.InitializeDatabaseConnection("mco") + if err != nil { + log.Println("Unable to initialize database connection...") + log.Println(err) + log.Fatalln("Exiting...") + } + err = contextDb.InitializeContextDatabase() + if err != nil { + log.Println("Unable to initialize database connection...") + log.Println(err) + log.Fatalln("Exiting...") + } + + httpRouter := api.NewRouter(nil) + loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter) + log.Println("Starting Network Customization Manager") + + httpServer := &http.Server{ + Handler: loggedRouter, + Addr: ":" + config.GetConfiguration().ServicePort, + } + + go func() { + err := startGrpcServer() + if err != nil { + log.Fatalf("GRPC server failed to start") + } + }() + + connectionsClose := make(chan struct{}) + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c + httpServer.Shutdown(context.Background()) + close(connectionsClose) + }() + + tlsConfig, err := auth.GetTLSConfig("ca.cert", "server.cert", "server.key") + if err != nil { + log.Println("Error Getting TLS Configuration. Starting without TLS...") + log.Fatal(httpServer.ListenAndServe()) + } else { + httpServer.TLSConfig = tlsConfig + // empty strings because tlsconfig already has this information + err = httpServer.ListenAndServeTLS("", "") + } +} diff --git a/src/ovnaction/config.json b/src/ovnaction/config.json new file mode 100644 index 00000000..4751ebe2 --- /dev/null +++ b/src/ovnaction/config.json @@ -0,0 +1,10 @@ +{ + "database-ip": "172.18.0.2", + "database-type": "mongo", + "plugin-dir": "plugins", + "service-port": "9018", + "grpc-server-cert": "/home/ewmulta/onap/frankfort/orchestrator/ca/ncm.crt", + "grpc-server-key": "/home/ewmulta/onap/frankfort/orchestrator/ca/ncm.key", + "grpc-enable-tls": "disable", + "grpc-server-name-override": "" +} diff --git a/src/ovnaction/go.mod b/src/ovnaction/go.mod new file mode 100644 index 00000000..5f0ed5dd --- /dev/null +++ b/src/ovnaction/go.mod @@ -0,0 +1,36 @@ +module github.com/onap/multicloud-k8s/src/ovnaction + +require ( + github.com/ghodss/yaml v1.0.0 + github.com/go-stack/stack v1.8.0 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/gorilla/handlers v1.3.0 + github.com/gorilla/mux v1.6.2 + github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20200127152046-0ee521d56061 + github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee + github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-00010101000000-000000000000 + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/pkg/errors v0.8.1 + github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect + github.com/xdg/stringprep v1.0.0 // indirect + google.golang.org/grpc v1.27.1 + gopkg.in/yaml.v2 v2.2.8 + k8s.io/api v0.0.0-20190831074750-7364b6bdad65 + k8s.io/apimachinery v0.0.0-20190831074630-461753078381 + k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible + k8s.io/kubernetes v1.14.1 +) + +replace ( + github.com/onap/multicloud-k8s/src/orchestrator => ../orchestrator + k8s.io/api => k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 + k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d + k8s.io/apiserver => k8s.io/apiserver v0.0.0-20190409021813-1ec86e4da56c + k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20190409023024-d644b00f3b79 + k8s.io/client-go => k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible + k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190409023720-1bc0c81fa51d + +) + +go 1.13 diff --git a/src/ovnaction/go.sum b/src/ovnaction/go.sum new file mode 100644 index 00000000..ef936018 --- /dev/null +++ b/src/ovnaction/go.sum @@ -0,0 +1,626 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA= +github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.17.1+incompatible h1:PChbxFGKTWsg9IWh+pSZRCSj3zQkVpL6Hd9uWsFwxtc= +github.com/Masterminds/sprig v2.17.1+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/aokoli/goutils v1.1.0 h1:jy4ghdcYvs5EIoGssZNslIASX5m+KNMfyyKvRQ0TEVE= +github.com/aokoli/goutils v1.1.0/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 h1:HD4PLRzjuCVW79mQ0/pdsalOLHJ+FaEoqJLxfltpb2U= +github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.12+incompatible h1:pAWNwdf7QiT1zfaWyqCtNZQWCLByQyA3JrSQyuYAqnQ= +github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU= +github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190912223608-ad718029b705 h1:up4REDeXtcm77SlkowEGUuakgjpdNR2N9TkGTZSL4rM= +github.com/docker/docker v0.7.3-0.20190912223608-ad718029b705/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/engine v0.0.0-20190620014054-c513a4c6c298/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= +github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.10.0+incompatible h1:l6Soi8WCOOVAeCo4W98iBFC6Og7/X8bpRt51oNLZ2C8= +github.com/emicklei/go-restful v2.10.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= +github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= +github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.3.0 h1:tsg9qP3mjt1h4Roxp+M1paRjrVBfPSOpBuVclh6YluI= +github.com/gorilla/handlers v1.3.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.11.1 h1:/dBYI+n4xIL+Y9SKXQrjlKTmJJDwCSlNLRwZ5nBhIek= +github.com/grpc-ecosystem/grpc-gateway v1.11.1/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul v1.4.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.1/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 h1:/UewZcckqhvnnS0C6r3Sher2hSEbVmM6Ogpcjen08+Y= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20200127152046-0ee521d56061 h1:zz0mSqgjSJP6gqP2b7GdCiysj5OgD2DMJRNFJegLcs4= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20200127152046-0ee521d56061/go.mod h1:MP2HbArq3QT+oVp8pmtHNZnSnkhdkHtDnc7h6nJXmBU= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onap/multicloud-k8s v0.0.0-20200408054001-1e240a189cfc h1:LMRxrjWMbHnHUp+zbu8YCWUHj0q5/QfdS10sjXUHjGk= +github.com/onap/multicloud-k8s v0.0.0-20200410203632-335c7cca38eb h1:tZeR2RzC4GuNwVXzzoASgPpD5MIhGqm0G8usu6sS8wY= +github.com/onap/multicloud-k8s v0.0.0-20200413204718-f853b30cdc26 h1:gvCqIl3cfC6BUbPWtJNtiK8LQ8h5dam4mbR0P2aGQvs= +github.com/onap/multicloud-k8s v0.0.0-20200416220358-c898a84208d2 h1:oIQ3L7RXkgjZ+A6JD2q0eR2xTxLgIVULQPT0rKGRbqU= +github.com/onap/multicloud-k8s v0.0.0-20200420053546-41e63a840a08 h1:jhn67n5s5a/S6Qj01LF5gxhX316P/VYSbq6lU+swfUo= +github.com/onap/multicloud-k8s v0.0.0-20200421213921-bad55d7f0156 h1:JFxr/KGdNukBXPwxvKB+IDlnY8bYvMcOK4K4/txnfmM= +github.com/onap/multicloud-k8s v0.0.0-20200422173516-a25e24c34e4b h1:C5l/duGFWeeheN5tzzcH72Ec/3J0+takoSt58v14Ilk= +github.com/onap/multicloud-k8s v0.0.0-20200423214853-7e20d29b2d82 h1:3EDWZF3gzQuyxam+pK37o5gBPOLD5l7fcWs3kCrgeiw= +github.com/onap/multicloud-k8s v0.0.0-20200427194525-b8b6eaeea2fd h1:9xUOMEUP08x7y/ZxEuxWRVlzuUgENJPivsXdtsCEvlY= +github.com/onap/multicloud-k8s v0.0.0-20200430003646-7f6d2717e367 h1:q7wmGHDXWhjZJjHUWJ35ds0iMciG5DUQJBNpNu/zbSM= +github.com/onap/multicloud-k8s v0.0.0-20200511064412-8e0c00c4c59a h1:tKeUmKdcVneC0osJI8bO/WJhO2OPGzma6i4JXngovKQ= +github.com/onap/multicloud-k8s v0.0.0-20200513000418-bd3e69e7a26a h1:xCL9LxojS5TsuXMAbgc3Jbrpn8iHNViMU3LlRvbOPnk= +github.com/onap/multicloud-k8s v0.0.0-20200514000549-22a56b401408 h1:MZneQao7qtfrZPdmnScoCGPMrkMe6SaIQOpc3cw1GOk= +github.com/onap/multicloud-k8s v0.0.0-20200515230117-dbc92bae58ff h1:dS5KQvlCDbiIjQdM3Tc1ltGICW46+6nxhWLjYxOVZ4M= +github.com/onap/multicloud-k8s v0.0.0-20200520232550-eb3eac7c732d h1:tPtuX0jb/OasCAbkZzp55DA9aF5w23bxubWd6cp3W8M= +github.com/onap/multicloud-k8s v0.0.0-20200521042953-2b63abfd3033 h1:N6B6PKKAmVhiXz2H4jcp4uQjU6Cg8NklyaJ9RzBv2us= +github.com/onap/multicloud-k8s v0.0.0-20200521190055-10b401413dd7 h1:TVnSDjSwgrHoHu8th8l5T/F/tBhpF8LUYUB9nPfWhR8= +github.com/onap/multicloud-k8s v0.0.0-20200529003854-0a7bf256bde5 h1:NeFxBg7nuWQKe1bbFAsRrd7EbwJ2euu54GPx7EYhM+8= +github.com/onap/multicloud-k8s/src/k8splugin v0.0.0-20191115005109-f168ebb73d8d h1:ucIEjqzNVeFPnQofeuBfUqro0OnilX//fajEFxuLsgA= +github.com/onap/multicloud-k8s/src/k8splugin v0.0.0-20191115005109-f168ebb73d8d/go.mod h1:EnQd/vQGZR1/55IihaHxiux4ZUig/zfXZux7bfmU0S8= +github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200508014334-1449bbe36e44/go.mod h1:K7jYyPRlMAjgAycn6axOkzjaXHZ/j9+X1M+Vtar5cLA= +github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200511064412-8e0c00c4c59a/go.mod h1:K7jYyPRlMAjgAycn6axOkzjaXHZ/j9+X1M+Vtar5cLA= +github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200514000549-22a56b401408/go.mod h1:q6s8c45A2NN2V4lxciJ7OmCZFaS1uQSWaGxGG3UM3kM= +github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee h1:/PdsvtVvzmDdeQBswNrJlVEi3Q86p/jOv3z6XMi8Nu4= +github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee/go.mod h1:q6s8c45A2NN2V4lxciJ7OmCZFaS1uQSWaGxGG3UM3kM= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200407064900-ec83b3d3bda5 h1:mcqDx91zA9vNWAWz2fZJ60dxQR8bTafRs9YlQWnPvIg= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200407064900-ec83b3d3bda5/go.mod h1:tAKrUVGJa0hwzIcE1e09B5CtcI9ZXlL7ZMQiw4dXEhQ= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200408054001-1e240a189cfc h1:S5fSMB6hoFX3ruRaIovKDN3ZriVO6Dmn4K3ZzkeCP9U= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200408054001-1e240a189cfc/go.mod h1:tAKrUVGJa0hwzIcE1e09B5CtcI9ZXlL7ZMQiw4dXEhQ= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200410203632-335c7cca38eb h1:+zoJAQ8QV3ID8FxwGIp1FsxsSvyc3t5yz9KA9RE720U= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200413204718-f853b30cdc26 h1:78c4pv5dNEraV53mNIPJAbO3IElR5Ulgfj83WOFq5kY= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200413204718-f853b30cdc26/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200416220358-c898a84208d2 h1:TrtOaPpOvDgpycaIBFl5ohOe9/4uBBxIhLEg1TCTS2g= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200416220358-c898a84208d2/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200420053546-41e63a840a08 h1:yQUnAGVbPk48iwQ/dDHUSZaMnB8HwZmjOO0S4EsYowE= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200420053546-41e63a840a08/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200421213921-bad55d7f0156 h1:Lr+04i+d91x4k764QRoPpJdQ95Ilv2zvHEOL8rt1PPg= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200421213921-bad55d7f0156/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200422173516-a25e24c34e4b h1:3NwpbkhzDUSP0uUtkQLLpIgFzFP9uqq/zYVcB5elkxo= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200422173516-a25e24c34e4b/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200423214853-7e20d29b2d82 h1:IgTZnOsjh3L9xfvapdgoDGyoU/MjLg1fJPLAe/8ehWM= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200423214853-7e20d29b2d82/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200427194525-b8b6eaeea2fd h1:2G9mnB4Bb+0JaVxcvWgdIFH1epdoIs+UV/0I0pYgEMA= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200427194525-b8b6eaeea2fd/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200430003646-7f6d2717e367 h1:+Kyds0LFenrdaVLUGVJcHRqEF6ox0HLFK+bhpvE5iv8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200430003646-7f6d2717e367/go.mod h1:l+McjmNmpsgUku+EAqVvrHnsnwBOytDVlskzkAA7LK8= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200511064412-8e0c00c4c59a h1:j37m84J5PcAYYm7X5aq/rNiAv7dTRby1UtijP28JctQ= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200511064412-8e0c00c4c59a/go.mod h1:sV45qUKyYX+S6+5teIkW70lWyoghNC6eY7PWvzDTbYY= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200513000418-bd3e69e7a26a h1:nZkwKurmp1hwf1IQdMneTe9huKrSs9/aSiCLs5tSUOw= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200513000418-bd3e69e7a26a/go.mod h1:sV45qUKyYX+S6+5teIkW70lWyoghNC6eY7PWvzDTbYY= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200514000549-22a56b401408 h1:tzOkEIA+sp5QHlINwB6Evu59YAtwDtiOMd4DYHEyQj4= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200514000549-22a56b401408/go.mod h1:sV45qUKyYX+S6+5teIkW70lWyoghNC6eY7PWvzDTbYY= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200515060444-c77850a75eee h1:lyE2WBnNpqwgwr4KsFKBzZTHMVtvrNp3q19HZcpStms= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200515060444-c77850a75eee/go.mod h1:sV45qUKyYX+S6+5teIkW70lWyoghNC6eY7PWvzDTbYY= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200520232550-eb3eac7c732d h1:DTYtqzSvRZUYFbLnQ9b/Oms4V9MuiobgXGF5Uj+pEL0= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200520232550-eb3eac7c732d/go.mod h1:zpEOrSrzSCEO2dqjW5nullfXbjs9UQOTiJdJxUCwirI= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200521042953-2b63abfd3033 h1:dLu/E31+9RMNgOi+dViNdsCEdClpO44a1GQSKbIVL9g= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200521042953-2b63abfd3033/go.mod h1:zpEOrSrzSCEO2dqjW5nullfXbjs9UQOTiJdJxUCwirI= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200521190055-10b401413dd7 h1:CouynDh1GS5hVxebIqonVXPlLh4BmGi0Ie5XsnZzilo= +github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200521190055-10b401413dd7/go.mod h1:zpEOrSrzSCEO2dqjW5nullfXbjs9UQOTiJdJxUCwirI= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200511064412-8e0c00c4c59a h1:EfsX/tT3ZOdVPmENaujBKKfWoYopmOXXaTAl2wc6EW4= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200513000418-bd3e69e7a26a h1:K2kF2K9xwuOLGyuv6jRPla4g6kYilZW6pE8jhOEE3uM= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200514000549-22a56b401408 h1:HJuCZdxmBLB8VQmpaKqRpv34T6Fg/SNVLPqZTfW0bUs= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200515230117-dbc92bae58ff h1:ZXJaVyzk1u5dVyPqgJoe5rVwYp/sIDTX77b7R8K/hVM= +github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200521190055-10b401413dd7 h1:KLDBRjXJMErrPFQGStJa8p/ee8dJ30w4OT4OnP6JuSg= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1 h1:G7j/gxkXAL80NMLOWi6EEctDET1Iuxl3sBMJXDnu2z0= +github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245 h1:DNVk+NIkGS0RbLkjQOLCJb/759yfCysThkMbl7EXxyY= +github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245/go.mod h1:O1c8HleITsZqzNZDjSNzirUGsMT0oGu9LhHKoJrqO+A= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 h1:BP2bjP495BBPaBcS5rmqviTfrOkN5rO5ceKAMRZCRFc= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v3.3.12+incompatible h1:V6PRYRGpU4k5EajJaaj/GL3hqIdzyPnBU8aPUp+35yw= +go.etcd.io/etcd v3.3.12+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c= +go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190927073244-c990c680b611 h1:q9u40nxWT5zRClI/uU9dHCiYGottAg6Nzz4YUQyHxdA= +golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200305110556-506484158171 h1:xes2Q2k+d/+YNXVw0FpZkIDJiaux4OVrRKXRAzH6A0U= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= +gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= +gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo= +k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 h1:q1Qvjzs/iEdXF6A1a8H3AKVFDzJNcJn3nXMs6R6qFtA= +k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= +k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA= +k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apiserver v0.0.0-20190409021813-1ec86e4da56c h1:k7ALUVzrOEgz4hOF+pr4pePn7TqZ9lB/8Z8ndMSsWSU= +k8s.io/apiserver v0.0.0-20190409021813-1ec86e4da56c/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= +k8s.io/cli-runtime v0.0.0-20190409023024-d644b00f3b79 h1:bZyxc0wzVA5KgUfAXZA6z872zDWmyslwfvrr175VF68= +k8s.io/cli-runtime v0.0.0-20190409023024-d644b00f3b79/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM= +k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible h1:U5Bt+dab9K8qaUmXINrkXO135kA11/i5Kg1RUydgaMQ= +k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/cloud-provider v0.0.0-20190409023720-1bc0c81fa51d h1:ad7UpNUGRx6FbYoK4+xIYyeS2CUShjNKY45YN1ipjLI= +k8s.io/cloud-provider v0.0.0-20190409023720-1bc0c81fa51d/go.mod h1:LlIffnLBu+GG7d4ppPzC8UnA1Ex8S+ntmSRVsnr7Xy4= +k8s.io/code-generator v0.0.0-20181114232248-ae218e241252/go.mod h1:IPqxl/YHk05nodzupwjke6ctMjyNRdV2zZ5/j3/F204= +k8s.io/gengo v0.0.0-20181106084056-51747d6e00da/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190907103519-ebc107f98eab/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/helm v2.14.3+incompatible h1:uzotTcZXa/b2SWVoUzM1xiCXVjI38TuxMujS/1s+3Gw= +k8s.io/helm v2.14.3+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kubernetes v1.14.1 h1:I9F52h5sqVxBmoSsBlNQ0YygNcukDilkpGxUbJRoBoY= +k8s.io/kubernetes v1.14.1/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20190907131718-3d4f5b7dea0b h1:eMM0sTvh3KBVGwJfuNcU86P38TJhlVMAICbFPDG3t0M= +k8s.io/utils v0.0.0-20190907131718-3d4f5b7dea0b/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200327001022-6496210b90e8 h1:6JFbaLjRyBz8K2Jvt+pcT+N3vvwMZfg8MfVENwe9aag= +k8s.io/utils v0.0.0-20200327001022-6496210b90e8/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200411171748-3d5a2fe318e4 h1:vEYeh6f+jz98bCG4BHRQ733tuZpjzsJ+C/xv8awA0qM= +k8s.io/utils v0.0.0-20200411171748-3d5a2fe318e4/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200414100711-2df71ebbae66 h1:Ly1Oxdu5p5ZFmiVT71LFgeZETvMfZ1iBIGeOenT2JeM= +k8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200520001619-278ece378a50 h1:ZtTUW5+ZWaoqjR3zOpRa7oFJ5d4aA22l4me/xArfOIc= +k8s.io/utils v0.0.0-20200520001619-278ece378a50/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787 h1:O69FD9pJA4WUZlEwYatBEEkRWKQ5cKodWpdKTrCS/iQ= +vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go b/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go new file mode 100644 index 00000000..fc548ccc --- /dev/null +++ b/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go @@ -0,0 +1,45 @@ +/* +Copyright 2020 Intel Corporation. +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 contextupdateserver + +import ( + "context" + "encoding/json" + "log" + + contextpb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/contextupdate" + //"google.golang.org/grpc/codes" + //"google.golang.org/grpc/status" +) + +type contextupdateServer struct { + contextpb.UnimplementedContextupdateServer +} + +func (cs *contextupdateServer) UpdateAppContext(ctx context.Context, req *contextpb.ContextUpdateRequest) (*contextpb.ContextUpdateResponse, error) { + contextUpdateReq, _ := json.Marshal(req) + log.Println("GRPC Server received contextupdateRequest: ", string(contextUpdateReq)) + + // Insert call to Server Functionality here + // + // + + return &contextpb.ContextUpdateResponse{AppContextUpdated: true}, nil +} + +// NewContextUpdateServer exported +func NewContextupdateServer() *contextupdateServer { + s := &contextupdateServer{} + return s +} diff --git a/src/ovnaction/pkg/grpc/register.go b/src/ovnaction/pkg/grpc/register.go new file mode 100644 index 00000000..4a31cf9d --- /dev/null +++ b/src/ovnaction/pkg/grpc/register.go @@ -0,0 +1,58 @@ +/* +Copyright 2020 Intel Corporation. +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 grpc + +import ( + "os" + "strconv" + "strings" + + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" +) + +const default_host = "localhost" +const default_port = 9032 +const default_ovnaction_name = "ovnaction" +const ENV_OVNACTION_NAME = "OVNACTION_NAME" + +func GetServerHostPort() (string, int) { + + // expect name of this ncm program to be in env variable "OVNACTION_NAME" - e.g. OVNACTION_NAME="ncm" + serviceName := os.Getenv(ENV_OVNACTION_NAME) + if serviceName == "" { + serviceName = default_ovnaction_name + log.Info("Using default name for OVNACTION service name", log.Fields{ + "Name": serviceName, + }) + } + + // expect service name to be in env variable - e.g. OVNACTION_SERVICE_HOST + host := os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_HOST") + if host == "" { + host = default_host + log.Info("Using default host for ovnaction gRPC controller", log.Fields{ + "Host": host, + }) + } + + // expect service port to be in env variable - e.g. OVNACTION_SERVICE_PORT + port, err := strconv.Atoi(os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_PORT")) + if err != nil || port < 0 { + port = default_port + log.Info("Using default port for ovnaction gRPC controller", log.Fields{ + "Port": port, + }) + } + return host, port +} diff --git a/src/ovnaction/pkg/module/chaining.go b/src/ovnaction/pkg/module/chaining.go new file mode 100644 index 00000000..45f061fa --- /dev/null +++ b/src/ovnaction/pkg/module/chaining.go @@ -0,0 +1,209 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// Chain defines the high level structure of a network chain document +type Chain struct { + Metadata Metadata `json:"metadata" yaml:"metadata"` + Spec NetworkChainingSpec `json:"spec" yaml:"spec"` +} + +// NetworkChainingSpec contains the specification of a network chain +type NetworkChainingSpec struct { + ChainType string `json:"type"` + RoutingSpec RouteSpec `json:"routingSpec"` +} + +// RouteSpec contains the routing specificaiton of a network chain +type RouteSpec struct { + LeftNetwork []RoutingNetwork `json:"leftNetwork"` + RightNetwork []RoutingNetwork `json:"rightNetwork"` + NetworkChain string `json:"networkChain"` + Namespace string `json:"namespace"` +} + +// RoutingNetwork contains the route networkroute network details for en element of a network chain +type RoutingNetwork struct { + NetworkName string `json:"networkName"` + GatewayIP string `json:"gatewayIp"` + Subnet string `json:"subnet"` +} + +// ChainKey is the key structure that is used in the database +type ChainKey struct { + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + NetControlIntent string `json:"netcontrolintent"` + NetworkChain string `json:"networkchain"` +} + +// CrChain is the structure for the Network Chain Custom Resource +type CrChain struct { + APIVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Chain Chain +} + +// RoutingChainType is currently only defined chaining type +const RoutingChainType = "routing" + +// ChainingAPIVersion is the kubernetes version of a network chain custom resource +const ChainingAPIVersion = "k8s.plugin.opnfv.org/v1" + +// ChainingKind is the Kind string for a network chain +const ChainingKind = "NetworkChaining" + +// ChainManager is an interface exposing the Chain functionality +type ChainManager interface { + CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) + GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) + GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) + DeleteChain(name, pr, ca, caver, netctrlint string) error +} + +// ChainClient implements the Manager +// It will also be used to maintain some localized state +type ChainClient struct { + db ClientDbInfo +} + +// NewChainClient returns an instance of the ChainClient +// which implements the Manager +func NewChainClient() *ChainClient { + return &ChainClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "chainmetadata", + }, + } +} + +// CreateChain - create a new Chain +func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) { + //Construct key and tag to select the entry + key := ChainKey{ + Project: pr, + CompositeApp: ca, + CompositeAppVersion: caver, + NetControlIntent: netctrlint, + NetworkChain: ch.Metadata.Name, + } + + //Check if the Network Control Intent exists + _, err := NewNetControlIntentClient().GetNetControlIntent(netctrlint, pr, ca, caver) + if err != nil { + return Chain{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netctrlint) + } + + //Check if this Chain already exists + _, err = v.GetChain(ch.Metadata.Name, pr, ca, caver, netctrlint) + if err == nil && !exists { + return Chain{}, pkgerrors.New("Chain already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, ch) + if err != nil { + return Chain{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return ch, nil +} + +// GetChain returns the Chain for corresponding name +func (v *ChainClient) GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) { + //Construct key and tag to select the entry + key := ChainKey{ + Project: pr, + CompositeApp: ca, + CompositeAppVersion: caver, + NetControlIntent: netctrlint, + NetworkChain: name, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return Chain{}, pkgerrors.Wrap(err, "Get Chain") + } + + //value is a byte array + if value != nil { + ch := Chain{} + err = db.DBconn.Unmarshal(value[0], &ch) + if err != nil { + return Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return ch, nil + } + + return Chain{}, pkgerrors.New("Error getting Chain") +} + +// GetChains returns all of the Chains for for the given network control intent +func (v *ChainClient) GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) { + //Construct key and tag to select the entry + key := ChainKey{ + Project: pr, + CompositeApp: ca, + CompositeAppVersion: caver, + NetControlIntent: netctrlint, + NetworkChain: "", + } + + var resp []Chain + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []Chain{}, pkgerrors.Wrap(err, "Get Chains") + } + + for _, value := range values { + cp := Chain{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// DeleteChain deletes the Chain from the database +func (v *ChainClient) DeleteChain(name, pr, ca, caver, netctrlint string) error { + + //Construct key and tag to select the entry + key := ChainKey{ + Project: pr, + CompositeApp: ca, + CompositeAppVersion: caver, + NetControlIntent: netctrlint, + NetworkChain: name, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete Chain Entry;") + } + + return nil +} diff --git a/src/ovnaction/pkg/module/module.go b/src/ovnaction/pkg/module/module.go new file mode 100644 index 00000000..2b4b9358 --- /dev/null +++ b/src/ovnaction/pkg/module/module.go @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +// Client for using the services in the ncm +type Client struct { + NetControlIntent *NetControlIntentClient + WorkloadIntent *WorkloadIntentClient + WorkloadIfIntent *WorkloadIfIntentClient + Chain *ChainClient + // Add Clients for API's here +} + +// NewClient creates a new client for using the services +func NewClient() *Client { + c := &Client{} + c.NetControlIntent = NewNetControlIntentClient() + c.WorkloadIntent = NewWorkloadIntentClient() + c.WorkloadIfIntent = NewWorkloadIfIntentClient() + c.Chain = NewChainClient() + // Add Client API handlers here + return c +} diff --git a/src/ovnaction/pkg/module/module_definitions.go b/src/ovnaction/pkg/module/module_definitions.go new file mode 100644 index 00000000..a868fdaf --- /dev/null +++ b/src/ovnaction/pkg/module/module_definitions.go @@ -0,0 +1,68 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + pkgerrors "github.com/pkg/errors" +) + +const CNI_TYPE_OVN4NFV string = "ovn4nfv" + +var CNI_TYPES = [...]string{CNI_TYPE_OVN4NFV} + +// It implements the interface for managing the ClusterProviders +const MAX_DESCRIPTION_LEN int = 1024 +const MAX_USERDATA_LEN int = 4096 + +type Metadata struct { + Name string `json:"name" yaml:"name"` + Description string `json:"description" yaml:"-"` + UserData1 string `json:"userData1" yaml:"-"` + UserData2 string `json:"userData2" yaml:"-"` +} + +type ClientDbInfo struct { + storeName string // name of the mongodb collection to use for client documents + tagMeta string // attribute key name for the json data of a client document + tagContent string // attribute key name for the file data of a client document + tagContext string // attribute key name for context object in App Context +} + +// Check for valid format Metadata +func IsValidMetadata(metadata Metadata) error { + errs := validation.IsValidName(metadata.Name) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata name=[%v], errors: %v", metadata.Name, errs) + } + + errs = validation.IsValidString(metadata.Description, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.Description, errs) + } + + errs = validation.IsValidString(metadata.UserData1, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.UserData1, errs) + } + + errs = validation.IsValidString(metadata.UserData2, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.UserData2, errs) + } + + return nil +} diff --git a/src/ovnaction/pkg/module/netcontrolintent.go b/src/ovnaction/pkg/module/netcontrolintent.go new file mode 100644 index 00000000..c005a935 --- /dev/null +++ b/src/ovnaction/pkg/module/netcontrolintent.go @@ -0,0 +1,295 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "encoding/json" + "strings" + + jyaml "github.com/ghodss/yaml" + + nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + + pkgerrors "github.com/pkg/errors" +) + +// NetControlIntent contains the parameters needed for dynamic networks +type NetControlIntent struct { + Metadata Metadata `json:"metadata"` +} + +// NetControlIntentKey is the key structure that is used in the database +type NetControlIntentKey struct { + NetControlIntent string `json:"netcontrolintent"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` +} + +// Manager is an interface exposing the NetControlIntent functionality +type NetControlIntentManager interface { + CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) + GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) + GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) + DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error + ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error +} + +// NetControlIntentClient implements the Manager +// It will also be used to maintain some localized state +type NetControlIntentClient struct { + db ClientDbInfo +} + +// NewNetControlIntentClient returns an instance of the NetControlIntentClient +// which implements the Manager +func NewNetControlIntentClient() *NetControlIntentClient { + return &NetControlIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "netcontrolintentmetadata", + }, + } +} + +// CreateNetControlIntent - create a new NetControlIntent +func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: nci.Metadata.Name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + //Check if this NetControlIntent already exists + _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion) + if err == nil && !exists { + return NetControlIntent{}, pkgerrors.New("NetControlIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, nci) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return nci, nil +} + +// GetNetControlIntent returns the NetControlIntent for corresponding name +func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntent") + } + + //value is a byte array + if value != nil { + nci := NetControlIntent{} + err = db.DBconn.Unmarshal(value[0], &nci) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return nci, nil + } + + return NetControlIntent{}, pkgerrors.New("Error getting NetControlIntent") +} + +// GetNetControlIntentList returns all of the NetControlIntent for corresponding name +func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: "", + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + var resp []NetControlIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntents") + } + + for _, value := range values { + nci := NetControlIntent{} + err = db.DBconn.Unmarshal(value, &nci) + if err != nil { + return []NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, nci) + } + + return resp, nil +} + +// Delete the NetControlIntent from database +func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete NetControlIntent Entry;") + } + + return nil +} + +// (Test Routine) - Apply network-control-intent +func (v *NetControlIntentClient) ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error { + // TODO: Handle all Network Chain Intents for the Network Control Intent + + // Handle all Workload Intents for the Network Control Intent + wis, err := NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, name) + if err != nil { + return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", name, project, compositeapp, compositeappversion) + } + + // Setup the AppContext + var context appcontext.AppContext + _, err = context.LoadAppContext(appContextId) + if err != nil { + return pkgerrors.Wrapf(err, "Error getting AppContext with Id: %v for %v/%v%v", + appContextId, project, compositeapp, compositeappversion) + } + + // Handle all intents (currently just Interface intents) for each Workload Intent + for _, wi := range wis { + // The app/resource identified in the workload intent needs to be updated with two annotations. + // 1 - The "k8s.v1.cni.cncf.io/networks" annotation will have {"name": "ovn-networkobj", "namespace": "default"} added + // to it (preserving any existing values for this annotation. + // 2 - The "k8s.plugin.opnfv.org/nfn-network" annotation will add any network interfaces that are provided by the + // workload/interfaces intents. + + // Prepare the list of interfaces from the workload intent + wifs, err := NewWorkloadIfIntentClient().GetWorkloadIfIntents(project, + compositeapp, + compositeappversion, + name, + wi.Metadata.Name) + if err != nil { + return pkgerrors.Wrapf(err, + "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found", + wi.Metadata.Name, name, project, compositeapp, compositeappversion) + } + if len(wifs) == 0 { + log.Warn("No interface intents provided for workload intent", log.Fields{ + "project": project, + "composite app": compositeapp, + "composite app version": compositeappversion, + "network control intent": name, + "workload intent": wi.Metadata.Name, + }) + continue + } + + // Get all clusters for the current App from the AppContext + clusters, err := context.GetClusterNames(wi.Spec.AppName) + for _, c := range clusters { + rh, err := context.GetResourceHandle(wi.Spec.AppName, c, + strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+")) + if err != nil { + log.Warn("App Context resource handle not found", log.Fields{ + "project": project, + "composite app": compositeapp, + "composite app version": compositeappversion, + "network control intent": name, + "workload name": wi.Metadata.Name, + "app": wi.Spec.AppName, + "resource": wi.Spec.WorkloadResource, + "resource type": wi.Spec.Type, + }) + continue + } + r, err := context.GetValue(rh) + if err != nil { + log.Error("Error retrieving resource from App Context", log.Fields{ + "error": err, + "resource handle": rh, + }) + } + + // Unmarshal resource to K8S object + robj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string))) + + // Add network annotation to object + netAnnot := nettypes.NetworkSelectionElement{ + Name: "ovn-networkobj", + Namespace: "default", + } + AddNetworkAnnotation(robj, netAnnot) + + // Add nfn interface annotations to object + var newNfnIfs []WorkloadIfIntentSpec + for _, i := range wifs { + newNfnIfs = append(newNfnIfs, i.Spec) + } + AddNfnAnnotation(robj, newNfnIfs) + + // Marshal object back to yaml format (via json - seems to eliminate most clutter) + j, err := json.Marshal(robj) + if err != nil { + log.Error("Error marshalling resource to JSON", log.Fields{ + "error": err, + }) + continue + } + y, err := jyaml.JSONToYAML(j) + if err != nil { + log.Error("Error marshalling resource to YAML", log.Fields{ + "error": err, + }) + continue + } + + // Update resource in AppContext + err = context.UpdateResourceValue(rh, string(y)) + if err != nil { + log.Error("Network updating app context resource handle", log.Fields{ + "error": err, + "resource handle": rh, + }) + } + } + } + + return nil +} diff --git a/src/ovnaction/pkg/module/resources.go b/src/ovnaction/pkg/module/resources.go new file mode 100644 index 00000000..24c9833e --- /dev/null +++ b/src/ovnaction/pkg/module/resources.go @@ -0,0 +1,273 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "encoding/json" + "fmt" + + nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" + netutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils" + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" + v1 "k8s.io/api/apps/v1" + batch "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" + v1core "k8s.io/api/core/v1" + _ "k8s.io/kubernetes/pkg/apis/apps/install" + _ "k8s.io/kubernetes/pkg/apis/batch/install" + _ "k8s.io/kubernetes/pkg/apis/core/install" + _ "k8s.io/kubernetes/pkg/apis/extensions/install" + + pkgerrors "github.com/pkg/errors" +) + +type NfnAnnotation struct { + CniType string + Interface []WorkloadIfIntentSpec +} + +const NfnAnnotationKey = "k8s.plugin.opnfv.org/nfn-network" + +// ParsePodTemplateNetworkAnnotation parses Pod annotation in PodTemplate +func ParsePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec) ([]*nettypes.NetworkSelectionElement, error) { + netAnnot := pt.Annotations[nettypes.NetworkAttachmentAnnot] + defaultNamespace := pt.Namespace + + if len(netAnnot) == 0 { + return nil, pkgerrors.Errorf("No kubernetes network annotation found") + } + + networks, err := netutils.ParseNetworkAnnotation(netAnnot, defaultNamespace) + if err != nil { + return nil, err + } + return networks, nil +} + +// GetPodTemplateNetworkAnnotation gets Pod Nfn annotation in PodTemplate +func GetPodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec) NfnAnnotation { + var nfn NfnAnnotation + + nfnAnnot := pt.Annotations[NfnAnnotationKey] + if len(nfnAnnot) == 0 { + return nfn + } + + err := json.Unmarshal([]byte(nfnAnnot), &nfn) + if err != nil { + log.Warn("Error unmarshalling nfn annotation", log.Fields{ + "annotation": nfnAnnot, + }) + } + return nfn +} + +// GetPodNetworkAnnotation gets Pod Nfn annotation in PodTemplate +func GetPodNfnAnnotation(p *v1core.Pod) NfnAnnotation { + var nfn NfnAnnotation + + nfnAnnot := p.Annotations[NfnAnnotationKey] + if len(nfnAnnot) == 0 { + return nfn + } + + err := json.Unmarshal([]byte(nfnAnnot), &nfn) + if err != nil { + log.Warn("Error unmarshalling nfn annotation", log.Fields{ + "annotation": nfnAnnot, + }) + } + return nfn +} + +func addNetworkAnnotation(a nettypes.NetworkSelectionElement, as []*nettypes.NetworkSelectionElement) []*nettypes.NetworkSelectionElement { + var netElements []*nettypes.NetworkSelectionElement + + found := false + for _, e := range as { + if e.Name == a.Name { + found = true + } + netElements = append(netElements, e) + } + if !found { + netElements = append(netElements, &a) + } + + return netElements +} + +// Add the interfaces in the 'new' parameter to the nfn annotation +func newNfnIfs(nfn NfnAnnotation, new []WorkloadIfIntentSpec) NfnAnnotation { + // Prepare a new interface list - combining the original plus new ones + var newNfn NfnAnnotation + + if nfn.CniType != CNI_TYPE_OVN4NFV { + if len(nfn.CniType) > 0 { + log.Warn("Error existing nfn cnitype is invalid", log.Fields{ + "existing cnitype": nfn.CniType, + "using cnitype": CNI_TYPE_OVN4NFV, + }) + } + } + newNfn.CniType = CNI_TYPE_OVN4NFV + + // update any interfaces already in the list with the updated interface + for _, i := range nfn.Interface { + for _, j := range new { + if i.NetworkName == j.NetworkName && i.IfName == j.IfName { + i.DefaultGateway = j.DefaultGateway + i.IpAddr = j.IpAddr + i.MacAddr = j.MacAddr + break + } + } + newNfn.Interface = append(newNfn.Interface, i) + } + + // add new interfaces not present in original list + for _, j := range new { + found := false + for _, i := range nfn.Interface { + if i.NetworkName == j.NetworkName && i.IfName == j.IfName { + found = true + break + } + } + if !found { + newNfn.Interface = append(newNfn.Interface, j) + } + } + return newNfn +} + +func updatePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec, a nettypes.NetworkSelectionElement) { + netAnnotation, _ := ParsePodTemplateNetworkAnnotation(pt) + elements := addNetworkAnnotation(a, netAnnotation) + j, err := json.Marshal(elements) + if err != nil { + log.Error("Existing network annotation has invalid format", log.Fields{ + "error": err, + }) + return + } + if pt.Annotations == nil { + pt.Annotations = make(map[string]string) + } + pt.Annotations[nettypes.NetworkAttachmentAnnot] = string(j) +} + +// Add a network annotation to the resource +func AddNetworkAnnotation(r interface{}, a nettypes.NetworkSelectionElement) { + + switch o := r.(type) { + case *batch.Job: + updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) + case *batchv1beta1.CronJob: + updatePodTemplateNetworkAnnotation(&o.Spec.JobTemplate.Spec.Template, a) + case *v1.DaemonSet: + updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) + case *v1.Deployment: + updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) + case *v1.ReplicaSet: + updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) + case *v1.StatefulSet: + updatePodTemplateNetworkAnnotation(&o.Spec.Template, a) + case *v1core.Pod: + netAnnotation, _ := netutils.ParsePodNetworkAnnotation(o) + elements := addNetworkAnnotation(a, netAnnotation) + j, err := json.Marshal(elements) + if err != nil { + log.Error("Existing network annotation has invalid format", log.Fields{ + "error": err, + }) + break + } + if o.Annotations == nil { + o.Annotations = make(map[string]string) + } + o.Annotations[nettypes.NetworkAttachmentAnnot] = string(j) + return + case *v1core.ReplicationController: + updatePodTemplateNetworkAnnotation(o.Spec.Template, a) + default: + typeStr := fmt.Sprintf("%T", o) + log.Warn("Network annotations not supported for resource type", log.Fields{ + "resource type": typeStr, + }) + } +} + +func updatePodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec, new []WorkloadIfIntentSpec) { + nfnAnnotation := GetPodTemplateNfnAnnotation(pt) + newNfnAnnotation := newNfnIfs(nfnAnnotation, new) + j, err := json.Marshal(newNfnAnnotation) + if err != nil { + log.Error("Network nfn annotation has invalid format", log.Fields{ + "error": err, + }) + return + } + if pt.Annotations == nil { + pt.Annotations = make(map[string]string) + } + pt.Annotations[NfnAnnotationKey] = string(j) +} + +// Add an nfn annotation to the resource +func AddNfnAnnotation(r interface{}, new []WorkloadIfIntentSpec) { + + switch o := r.(type) { + case *batch.Job: + updatePodTemplateNfnAnnotation(&o.Spec.Template, new) + case *batchv1beta1.CronJob: + updatePodTemplateNfnAnnotation(&o.Spec.JobTemplate.Spec.Template, new) + case *v1.DaemonSet: + updatePodTemplateNfnAnnotation(&o.Spec.Template, new) + return + case *v1.Deployment: + updatePodTemplateNfnAnnotation(&o.Spec.Template, new) + return + case *v1.ReplicaSet: + updatePodTemplateNfnAnnotation(&o.Spec.Template, new) + case *v1.StatefulSet: + updatePodTemplateNfnAnnotation(&o.Spec.Template, new) + case *v1core.Pod: + nfnAnnotation := GetPodNfnAnnotation(o) + newNfnAnnotation := newNfnIfs(nfnAnnotation, new) + j, err := json.Marshal(newNfnAnnotation) + if err != nil { + log.Error("Network nfn annotation has invalid format", log.Fields{ + "error": err, + }) + break + } + if o.Annotations == nil { + o.Annotations = make(map[string]string) + } + o.Annotations[NfnAnnotationKey] = string(j) + return + case *v1core.ReplicationController: + updatePodTemplateNfnAnnotation(o.Spec.Template, new) + return + default: + typeStr := fmt.Sprintf("%T", o) + log.Warn("Network nfn annotations not supported for resource type", log.Fields{ + "resource type": typeStr, + }) + } +} diff --git a/src/ovnaction/pkg/module/workloadifintent.go b/src/ovnaction/pkg/module/workloadifintent.go new file mode 100644 index 00000000..55062564 --- /dev/null +++ b/src/ovnaction/pkg/module/workloadifintent.go @@ -0,0 +1,188 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// WorkloadIfIntent contains the parameters needed for dynamic networks +type WorkloadIfIntent struct { + Metadata Metadata `json:"metadata"` + Spec WorkloadIfIntentSpec `json:"spec"` +} + +type WorkloadIfIntentSpec struct { + IfName string `json:"interface"` + NetworkName string `json:"name"` + DefaultGateway string `json:"defaultGateway"` // optional, default value is "false" + IpAddr string `json:"ipAddress,omitempty"` // optional, if not provided then will be dynamically allocated + MacAddr string `json:"macAddress,omitempty"` // optional, if not provided then will be dynamically allocated +} + +// WorkloadIfIntentKey is the key structure that is used in the database +type WorkloadIfIntentKey struct { + Project string `json:"provider"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + NetControlIntent string `json:"netcontrolintent"` + WorkloadIntent string `json:"workloadintent"` + WorkloadIfIntent string `json:"workloadifintent"` +} + +// Manager is an interface exposing the WorkloadIfIntent functionality +type WorkloadIfIntentManager interface { + CreateWorkloadIfIntent(wi WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) + GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) + GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) + DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error +} + +// WorkloadIfIntentClient implements the Manager +// It will also be used to maintain some localized state +type WorkloadIfIntentClient struct { + db ClientDbInfo +} + +// NewWorkloadIfIntentClient returns an instance of the WorkloadIfIntentClient +// which implements the Manager +func NewWorkloadIfIntentClient() *WorkloadIfIntentClient { + return &WorkloadIfIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "workloadifintentmetadata", + }, + } +} + +// CreateWorkloadIfIntent - create a new WorkloadIfIntent +func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: wif.Metadata.Name, + } + + //Check if the Workload Intent exists + _, err := NewWorkloadIntentClient().GetWorkloadIntent(workloadintent, project, compositeapp, compositeappversion, netcontrolintent) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Errorf("Workload Intent %v does not exist", workloadintent) + } + + //Check if this WorkloadIfIntent already exists + _, err = v.GetWorkloadIfIntent(wif.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent) + if err == nil && !exists { + return WorkloadIfIntent{}, pkgerrors.New("WorkloadIfIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wif) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return wif, nil +} + +// GetWorkloadIfIntent returns the WorkloadIfIntent for corresponding name +func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: name, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntent") + } + + //value is a byte array + if value != nil { + wif := WorkloadIfIntent{} + err = db.DBconn.Unmarshal(value[0], &wif) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return wif, nil + } + + return WorkloadIfIntent{}, pkgerrors.New("Error getting WorkloadIfIntent") +} + +// GetWorkloadIfIntentList returns all of the WorkloadIfIntent for corresponding name +func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: "", + } + + var resp []WorkloadIfIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntents") + } + + for _, value := range values { + wif := WorkloadIfIntent{} + err = db.DBconn.Unmarshal(value, &wif) + if err != nil { + return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, wif) + } + + return resp, nil +} + +// Delete the WorkloadIfIntent from database +func (v *WorkloadIfIntentClient) DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: name, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete WorkloadIfIntent Entry;") + } + + return nil +} diff --git a/src/ovnaction/pkg/module/workloadintent.go b/src/ovnaction/pkg/module/workloadintent.go new file mode 100644 index 00000000..e6916954 --- /dev/null +++ b/src/ovnaction/pkg/module/workloadintent.go @@ -0,0 +1,181 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// WorkloadIntent contains the parameters needed for dynamic networks +type WorkloadIntent struct { + Metadata Metadata `json:"metadata"` + Spec WorkloadIntentSpec `json:"spec"` +} + +type WorkloadIntentSpec struct { + AppName string `json:"application-name"` + WorkloadResource string `json:"workload-resource"` + Type string `json:"type"` +} + +// WorkloadIntentKey is the key structure that is used in the database +type WorkloadIntentKey struct { + Project string `json:"provider"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + NetControlIntent string `json:"netcontrolintent"` + WorkloadIntent string `json:"workloadintent"` +} + +// Manager is an interface exposing the WorkloadIntent functionality +type WorkloadIntentManager interface { + CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) + GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) + GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) + DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error +} + +// WorkloadIntentClient implements the Manager +// It will also be used to maintain some localized state +type WorkloadIntentClient struct { + db ClientDbInfo +} + +// NewWorkloadIntentClient returns an instance of the WorkloadIntentClient +// which implements the Manager +func NewWorkloadIntentClient() *WorkloadIntentClient { + return &WorkloadIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "workloadintentmetadata", + }, + } +} + +// CreateWorkloadIntent - create a new WorkloadIntent +func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: wi.Metadata.Name, + } + + //Check if the Network Control Intent exists + _, err := NewNetControlIntentClient().GetNetControlIntent(netcontrolintent, project, compositeapp, compositeappversion) + if err != nil { + return WorkloadIntent{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netcontrolintent) + } + + //Check if this WorkloadIntent already exists + _, err = v.GetWorkloadIntent(wi.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent) + if err == nil && !exists { + return WorkloadIntent{}, pkgerrors.New("WorkloadIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wi) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return wi, nil +} + +// GetWorkloadIntent returns the WorkloadIntent for corresponding name +func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: name, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntent") + } + + //value is a byte array + if value != nil { + wi := WorkloadIntent{} + err = db.DBconn.Unmarshal(value[0], &wi) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return wi, nil + } + + return WorkloadIntent{}, pkgerrors.New("Error getting WorkloadIntent") +} + +// GetWorkloadIntentList returns all of the WorkloadIntent for corresponding name +func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: "", + } + + var resp []WorkloadIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntents") + } + + for _, value := range values { + wi := WorkloadIntent{} + err = db.DBconn.Unmarshal(value, &wi) + if err != nil { + return []WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, wi) + } + + return resp, nil +} + +// Delete the WorkloadIntent from database +func (v *WorkloadIntentClient) DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: name, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete WorkloadIntent Entry;") + } + + return nil +} diff --git a/src/ovnaction/scripts/Dockerfile b/src/ovnaction/scripts/Dockerfile new file mode 100644 index 00000000..a9d4d467 --- /dev/null +++ b/src/ovnaction/scripts/Dockerfile @@ -0,0 +1,30 @@ +# SPDX-license-identifier: Apache-2.0 +############################################################################## +# Copyright (c) 2020 +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +FROM ubuntu:18.04 + +ARG HTTP_PROXY=${HTTP_PROXY} +ARG HTTPS_PROXY=${HTTPS_PROXY} + +ENV http_proxy $HTTP_PROXY +ENV https_proxy $HTTPS_PROXY +ENV no_proxy $NO_PROXY + +EXPOSE 9016 + +RUN groupadd -r onap && useradd -r -g onap onap + +WORKDIR /opt/multicloud/k8s/ovnaction +RUN chown onap:onap /opt/multicloud/k8s/ovnaction -R + +ADD --chown=onap ./ovnaction ./ + +USER onap + +CMD ["./ovnaction"] -- cgit 1.2.3-korg