From e201896e60374698da18cf4258448a0d97617e37 Mon Sep 17 00:00:00 2001 From: Eric Multanen Date: Thu, 12 Mar 2020 15:59:24 -0700 Subject: Create network service with cluster API Creates a new network customization and configuration service. Seed it by moving the cluster-provider and cluster API from the orchestrator service to this new service. More APIs to follow. Just put a Dockerfile in the ncm/scripts directory for now. See: https://wiki.onap.org/pages/viewpage.action?pageId=79201398 Issue-ID: MULTICLOUD-1029 Signed-off-by: Eric Multanen Change-Id: Iea1b1151e5f87fecaca9cfe8c9746a59eb447a7a --- src/ncm/Makefile | 36 + src/ncm/api/api.go | 76 ++ src/ncm/api/clusterhandler.go | 468 +++++++ src/ncm/api/clusterhandler_test.go | 1412 ++++++++++++++++++++ src/ncm/api/testing.go | 31 + src/ncm/cmd/main.go | 77 ++ src/ncm/go.mod | 31 + src/ncm/pkg/module/cluster.go | 540 ++++++++ src/ncm/pkg/module/module.go | 31 + src/ncm/scripts/Dockerfile | 30 + src/ncm/tests/certs/auth_test_certificate.pem | 21 + src/ncm/tests/certs/auth_test_key.pem | 28 + src/ncm/tests/configs/mock_config.json | 5 + src/orchestrator/api/api.go | 23 - src/orchestrator/api/clusterhandler.go | 468 ------- src/orchestrator/api/clusterhandler_test.go | 1412 -------------------- .../api/composite_profilehandler_test.go | 2 +- src/orchestrator/api/controllerhandler_test.go | 6 +- src/orchestrator/api/projecthandler_test.go | 6 +- src/orchestrator/cmd/main.go | 2 +- src/orchestrator/pkg/module/cluster.go | 540 -------- src/orchestrator/pkg/module/module.go | 2 - 22 files changed, 2794 insertions(+), 2453 deletions(-) create mode 100644 src/ncm/Makefile create mode 100644 src/ncm/api/api.go create mode 100644 src/ncm/api/clusterhandler.go create mode 100644 src/ncm/api/clusterhandler_test.go create mode 100644 src/ncm/api/testing.go create mode 100644 src/ncm/cmd/main.go create mode 100644 src/ncm/go.mod create mode 100644 src/ncm/pkg/module/cluster.go create mode 100644 src/ncm/pkg/module/module.go create mode 100644 src/ncm/scripts/Dockerfile create mode 100644 src/ncm/tests/certs/auth_test_certificate.pem create mode 100644 src/ncm/tests/certs/auth_test_key.pem create mode 100644 src/ncm/tests/configs/mock_config.json delete mode 100644 src/orchestrator/api/clusterhandler.go delete mode 100644 src/orchestrator/api/clusterhandler_test.go delete mode 100644 src/orchestrator/pkg/module/cluster.go diff --git a/src/ncm/Makefile b/src/ncm/Makefile new file mode 100644 index 00000000..fbdd53f7 --- /dev/null +++ b/src/ncm/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 ./ncm ./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 ncm 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/ncm/api/api.go b/src/ncm/api/api.go new file mode 100644 index 00000000..c26f54e9 --- /dev/null +++ b/src/ncm/api/api.go @@ -0,0 +1,76 @@ +/* + * 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/ncm/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.ClusterClient: + if testClient != nil && reflect.TypeOf(testClient).Implements(reflect.TypeOf((*moduleLib.ClusterManager)(nil)).Elem()) { + c, ok := testClient.(moduleLib.ClusterManager) + 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() + + clusterHandler := clusterHandler{ + client: setClient(moduleClient.Cluster, testClient).(moduleLib.ClusterManager), + } + + router := mux.NewRouter().PathPrefix("/v2").Subrouter() + + router.HandleFunc("/cluster-providers", clusterHandler.createClusterProviderHandler).Methods("POST") + router.HandleFunc("/cluster-providers", clusterHandler.getClusterProviderHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{name}", clusterHandler.getClusterProviderHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{name}", clusterHandler.deleteClusterProviderHandler).Methods("DELETE") + router.HandleFunc("/cluster-providers/{provider-name}/clusters", clusterHandler.createClusterHandler).Methods("POST") + router.HandleFunc("/cluster-providers/{provider-name}/clusters", clusterHandler.getClusterHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{name}", clusterHandler.getClusterHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{name}", clusterHandler.deleteClusterHandler).Methods("DELETE") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels", clusterHandler.createClusterLabelHandler).Methods("POST") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels", clusterHandler.getClusterLabelHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels/{label}", clusterHandler.getClusterLabelHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels/{label}", clusterHandler.deleteClusterLabelHandler).Methods("DELETE") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs", clusterHandler.createClusterKvPairsHandler).Methods("POST") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs", clusterHandler.getClusterKvPairsHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs/{kvpair}", clusterHandler.getClusterKvPairsHandler).Methods("GET") + router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs/{kvpair}", clusterHandler.deleteClusterKvPairsHandler).Methods("DELETE") + + return router +} diff --git a/src/ncm/api/clusterhandler.go b/src/ncm/api/clusterhandler.go new file mode 100644 index 00000000..cb147a8a --- /dev/null +++ b/src/ncm/api/clusterhandler.go @@ -0,0 +1,468 @@ +/* + * 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 ( + "bytes" + "encoding/base64" + "encoding/json" + "io" + "io/ioutil" + "mime" + "mime/multipart" + "net/http" + "net/textproto" + + moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" + + "github.com/gorilla/mux" +) + +// Used to store backend implementations objects +// Also simplifies mocking for unit testing purposes +type clusterHandler struct { + // Interface that implements Cluster operations + // We will set this variable with a mock interface for testing + client moduleLib.ClusterManager +} + +// Create handles creation of the ClusterProvider entry in the database +func (h clusterHandler) createClusterProviderHandler(w http.ResponseWriter, r *http.Request) { + var p moduleLib.ClusterProvider + + err := json.NewDecoder(r.Body).Decode(&p) + + 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 p.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + ret, err := h.client.CreateClusterProvider(p) + 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 ClusterProvider Name +// Returns a ClusterProvider +func (h clusterHandler) getClusterProviderHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + var ret interface{} + var err error + + if len(name) == 0 { + ret, err = h.client.GetClusterProviders() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetClusterProvider(name) + 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 ClusterProvider Name +func (h clusterHandler) deleteClusterProviderHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["name"] + + err := h.client.DeleteClusterProvider(name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// Create handles creation of the Cluster entry in the database +func (h clusterHandler) createClusterHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + var p moduleLib.Cluster + var q moduleLib.ClusterContent + + // Implemenation using multipart form + // Review and enable/remove at a later date + // Set Max size to 16mb here + err := r.ParseMultipartForm(16777216) + if err != nil { + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + jsn := bytes.NewBuffer([]byte(r.FormValue("metadata"))) + err = json.NewDecoder(jsn).Decode(&p) + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + //Read the file section and ignore the header + file, _, err := r.FormFile("file") + if err != nil { + http.Error(w, "Unable to process file", http.StatusUnprocessableEntity) + return + } + + defer file.Close() + + //Convert the file content to base64 for storage + content, err := ioutil.ReadAll(file) + if err != nil { + http.Error(w, "Unable to read file", http.StatusUnprocessableEntity) + return + } + + q.Kubeconfig = base64.StdEncoding.EncodeToString(content) + + // Name is required. + if p.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + ret, err := h.client.CreateCluster(provider, p, q) + 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 Cluster Name +// Returns a Cluster +func (h clusterHandler) getClusterHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + name := vars["name"] + + // handle the get all clusters case - return a list of only the json parts + if len(name) == 0 { + var retList []moduleLib.Cluster + + ret, err := h.client.GetClusters(provider) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + for _, cl := range ret { + retList = append(retList, moduleLib.Cluster{Metadata: cl.Metadata}) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(retList) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + return + } + + accepted, _, err := mime.ParseMediaType(r.Header.Get("Accept")) + if err != nil { + http.Error(w, err.Error(), http.StatusNotAcceptable) + return + } + + retCluster, err := h.client.GetCluster(provider, name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + retKubeconfig, err := h.client.GetClusterContent(provider, name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + switch accepted { + case "multipart/form-data": + mpw := multipart.NewWriter(w) + w.Header().Set("Content-Type", mpw.FormDataContentType()) + w.WriteHeader(http.StatusOK) + pw, err := mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json"}, "Content-Disposition": {"form-data; name=metadata"}}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if err := json.NewEncoder(pw).Encode(retCluster); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + pw, err = mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"form-data; name=file; filename=kubeconfig"}}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _, err = pw.Write(kcBytes) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + case "application/json": + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(retCluster) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + case "application/octet-stream": + w.Header().Set("Content-Type", "application/octet-stream") + w.WriteHeader(http.StatusOK) + kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _, err = w.Write(kcBytes) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + default: + http.Error(w, "set Accept: multipart/form-data, application/json or application/octet-stream", http.StatusMultipleChoices) + return + } +} + +// Delete handles DELETE operations on a particular Cluster Name +func (h clusterHandler) deleteClusterHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + name := vars["name"] + + err := h.client.DeleteCluster(provider, name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// Create handles creation of the ClusterLabel entry in the database +func (h clusterHandler) createClusterLabelHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + var p moduleLib.ClusterLabel + + err := json.NewDecoder(r.Body).Decode(&p) + + // LabelName is required. + if p.LabelName == "" { + http.Error(w, "Missing label name in POST request", http.StatusBadRequest) + return + } + + ret, err := h.client.CreateClusterLabel(provider, cluster, p) + 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 Cluster Label +// Returns a ClusterLabel +func (h clusterHandler) getClusterLabelHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + label := vars["label"] + + var ret interface{} + var err error + + if len(label) == 0 { + ret, err = h.client.GetClusterLabels(provider, cluster) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetClusterLabel(provider, cluster, label) + 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 ClusterLabel Name +func (h clusterHandler) deleteClusterLabelHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + label := vars["label"] + + err := h.client.DeleteClusterLabel(provider, cluster, label) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// Create handles creation of the ClusterKvPairs entry in the database +func (h clusterHandler) createClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + var p moduleLib.ClusterKvPairs + + err := json.NewDecoder(r.Body).Decode(&p) + + // KvPairsName is required. + if p.Metadata.Name == "" { + http.Error(w, "Missing Key Value pair name in POST request", http.StatusBadRequest) + return + } + + ret, err := h.client.CreateClusterKvPairs(provider, cluster, p) + 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 Cluster Key Value Pair +// Returns a ClusterKvPairs +func (h clusterHandler) getClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + kvpair := vars["kvpair"] + + var ret interface{} + var err error + + if len(kvpair) == 0 { + ret, err = h.client.GetAllClusterKvPairs(provider, cluster) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + ret, err = h.client.GetClusterKvPairs(provider, cluster, kvpair) + 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 Cluster Name +func (h clusterHandler) deleteClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + provider := vars["provider-name"] + cluster := vars["cluster-name"] + kvpair := vars["kvpair"] + + err := h.client.DeleteClusterKvPairs(provider, cluster, kvpair) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/src/ncm/api/clusterhandler_test.go b/src/ncm/api/clusterhandler_test.go new file mode 100644 index 00000000..af5bd160 --- /dev/null +++ b/src/ncm/api/clusterhandler_test.go @@ -0,0 +1,1412 @@ +/* + * 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 ( + "bytes" + "encoding/json" + "io" + "mime/multipart" + "net/http" + "net/http/httptest" + "net/textproto" + "reflect" + "testing" + + moduleLib "github.com/onap/multicloud-k8s/src/ncm/pkg/module" + + pkgerrors "github.com/pkg/errors" +) + +//Creating an embedded interface via anonymous variable +//This allows us to make mockDB satisfy the DatabaseConnection +//interface even if we are not implementing all the methods in it +type mockClusterManager struct { + // Items and err will be used to customize each test + // via a localized instantiation of mockClusterManager + ClusterProviderItems []moduleLib.ClusterProvider + ClusterItems []moduleLib.Cluster + ClusterContentItems []moduleLib.ClusterContent + ClusterLabelItems []moduleLib.ClusterLabel + ClusterKvPairsItems []moduleLib.ClusterKvPairs + Err error +} + +func (m *mockClusterManager) CreateClusterProvider(inp moduleLib.ClusterProvider) (moduleLib.ClusterProvider, error) { + if m.Err != nil { + return moduleLib.ClusterProvider{}, m.Err + } + + return m.ClusterProviderItems[0], nil +} + +func (m *mockClusterManager) GetClusterProvider(name string) (moduleLib.ClusterProvider, error) { + if m.Err != nil { + return moduleLib.ClusterProvider{}, m.Err + } + + return m.ClusterProviderItems[0], nil +} + +func (m *mockClusterManager) GetClusterProviders() ([]moduleLib.ClusterProvider, error) { + if m.Err != nil { + return []moduleLib.ClusterProvider{}, m.Err + } + + return m.ClusterProviderItems, nil +} + +func (m *mockClusterManager) DeleteClusterProvider(name string) error { + return m.Err +} + +func (m *mockClusterManager) CreateCluster(provider string, inp moduleLib.Cluster, inq moduleLib.ClusterContent) (moduleLib.Cluster, error) { + if m.Err != nil { + return moduleLib.Cluster{}, m.Err + } + + return m.ClusterItems[0], nil +} + +func (m *mockClusterManager) GetCluster(provider, name string) (moduleLib.Cluster, error) { + if m.Err != nil { + return moduleLib.Cluster{}, m.Err + } + + return m.ClusterItems[0], nil +} + +func (m *mockClusterManager) GetClusterContent(provider, name string) (moduleLib.ClusterContent, error) { + if m.Err != nil { + return moduleLib.ClusterContent{}, m.Err + } + + return m.ClusterContentItems[0], nil +} + +func (m *mockClusterManager) GetClusters(provider string) ([]moduleLib.Cluster, error) { + if m.Err != nil { + return []moduleLib.Cluster{}, m.Err + } + + return m.ClusterItems, nil +} + +func (m *mockClusterManager) DeleteCluster(provider, name string) error { + return m.Err +} + +func (m *mockClusterManager) CreateClusterLabel(provider, cluster string, inp moduleLib.ClusterLabel) (moduleLib.ClusterLabel, error) { + if m.Err != nil { + return moduleLib.ClusterLabel{}, m.Err + } + + return m.ClusterLabelItems[0], nil +} + +func (m *mockClusterManager) GetClusterLabel(provider, cluster, label string) (moduleLib.ClusterLabel, error) { + if m.Err != nil { + return moduleLib.ClusterLabel{}, m.Err + } + + return m.ClusterLabelItems[0], nil +} + +func (m *mockClusterManager) GetClusterLabels(provider, cluster string) ([]moduleLib.ClusterLabel, error) { + if m.Err != nil { + return []moduleLib.ClusterLabel{}, m.Err + } + + return m.ClusterLabelItems, nil +} + +func (m *mockClusterManager) DeleteClusterLabel(provider, cluster, label string) error { + return m.Err +} + +func (m *mockClusterManager) CreateClusterKvPairs(provider, cluster string, inp moduleLib.ClusterKvPairs) (moduleLib.ClusterKvPairs, error) { + if m.Err != nil { + return moduleLib.ClusterKvPairs{}, m.Err + } + + return m.ClusterKvPairsItems[0], nil +} + +func (m *mockClusterManager) GetClusterKvPairs(provider, cluster, kvpair string) (moduleLib.ClusterKvPairs, error) { + if m.Err != nil { + return moduleLib.ClusterKvPairs{}, m.Err + } + + return m.ClusterKvPairsItems[0], nil +} + +func (m *mockClusterManager) GetAllClusterKvPairs(provider, cluster string) ([]moduleLib.ClusterKvPairs, error) { + if m.Err != nil { + return []moduleLib.ClusterKvPairs{}, m.Err + } + + return m.ClusterKvPairsItems, nil +} + +func (m *mockClusterManager) DeleteClusterKvPairs(provider, cluster, kvpair string) error { + return m.Err +} + +func TestClusterProviderCreateHandler(t *testing.T) { + testCases := []struct { + label string + reader io.Reader + expected moduleLib.ClusterProvider + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Missing Cluster Provider Body Failure", + expectedCode: http.StatusBadRequest, + clusterClient: &mockClusterManager{}, + }, + { + label: "Create Cluster Provider", + expectedCode: http.StatusCreated, + reader: bytes.NewBuffer([]byte(`{ + "metadata": { + "name": "clusterProviderTest", + "description": "testClusterProvider", + "userData1": "some user data 1", + "userData2": "some user data 2" + } + }`)), + expected: moduleLib.ClusterProvider{ + Metadata: moduleLib.Metadata{ + Name: "clusterProviderTest", + Description: "testClusterProvider", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterProviderItems: []moduleLib.ClusterProvider{ + { + Metadata: moduleLib.Metadata{ + Name: "clusterProviderTest", + Description: "testClusterProvider", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + }, + }, + { + label: "Missing ClusterProvider Name in Request Body", + reader: bytes.NewBuffer([]byte(`{ + "metadata": { + "description": "this is a test cluster provider", + "userData1": "some user data 1", + "userData2": "some user data 2" + } + }`)), + expectedCode: http.StatusBadRequest, + clusterClient: &mockClusterManager{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("POST", "/v2/cluster-providers", testCase.reader) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusCreated + if resp.StatusCode == http.StatusCreated { + got := moduleLib.ClusterProvider{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("createHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterProviderGetAllHandler(t *testing.T) { + + testCases := []struct { + label string + expected []moduleLib.ClusterProvider + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster Provider", + expectedCode: http.StatusOK, + expected: []moduleLib.ClusterProvider{ + { + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider1", + Description: "testClusterProvider 1 description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider2", + Description: "testClusterProvider 2 description", + UserData1: "some user data A", + UserData2: "some user data B", + }, + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterProviderItems: []moduleLib.ClusterProvider{ + { + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider1", + Description: "testClusterProvider 1 description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider2", + Description: "testClusterProvider 2 description", + UserData1: "some user data A", + UserData2: "some user data B", + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers", nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := []moduleLib.ClusterProvider{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterProviderGetHandler(t *testing.T) { + + testCases := []struct { + label string + expected moduleLib.ClusterProvider + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster Provider", + expectedCode: http.StatusOK, + expected: moduleLib.ClusterProvider{ + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider", + Description: "testClusterProvider description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + name: "testClusterProvider", + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterProviderItems: []moduleLib.ClusterProvider{ + { + Metadata: moduleLib.Metadata{ + Name: "testClusterProvider", + Description: "testClusterProvider description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + }, + }, + { + label: "Get Non-Existing Cluster Provider", + expectedCode: http.StatusInternalServerError, + name: "nonexistingclusterprovider", + clusterClient: &mockClusterManager{ + ClusterProviderItems: []moduleLib.ClusterProvider{}, + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := moduleLib.ClusterProvider{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterProviderDeleteHandler(t *testing.T) { + + testCases := []struct { + label string + name string + version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Delete Cluster Provider", + expectedCode: http.StatusNoContent, + name: "testClusterProvider", + clusterClient: &mockClusterManager{}, + }, + { + label: "Delete Non-Existing Cluster Provider", + expectedCode: http.StatusInternalServerError, + name: "testClusterProvider", + clusterClient: &mockClusterManager{ + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("DELETE", "/v2/cluster-providers/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + }) + } +} + +func TestClusterCreateHandler(t *testing.T) { + testCases := []struct { + label string + metadata string + kubeconfig string + expected moduleLib.Cluster + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Missing Cluster Body Failure", + expectedCode: http.StatusBadRequest, + clusterClient: &mockClusterManager{}, + }, + { + label: "Create Cluster", + expectedCode: http.StatusCreated, + metadata: ` +{ + "metadata": { + "name": "clusterTest", + "description": "this is test cluster", + "userData1": "some cluster data abc", + "userData2": "some cluster data def" + } +}`, + kubeconfig: `test contents +of a file attached +to the creation +of clusterTest +`, + expected: moduleLib.Cluster{ + Metadata: moduleLib.Metadata{ + Name: "clusterTest", + Description: "testCluster", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterProviderItems: []moduleLib.ClusterProvider{ + { + Metadata: moduleLib.Metadata{ + Name: "clusterProvider1", + Description: "ClusterProvider 1 description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + ClusterItems: []moduleLib.Cluster{ + { + Metadata: moduleLib.Metadata{ + Name: "clusterTest", + Description: "testCluster", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + ClusterContentItems: []moduleLib.ClusterContent{ + { + Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", + }, + }, + }, + }, + { + label: "Missing Cluster Name in Request Body", + expectedCode: http.StatusBadRequest, + metadata: ` +{ + "metadata": { + "description": "this is test cluster", + "userData1": "some cluster data abc", + "userData2": "some cluster data def" + } +}`, + kubeconfig: `test contents +of a file attached +to the creation +of clusterTest +`, + clusterClient: &mockClusterManager{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + // Create the multipart test Request body + body := new(bytes.Buffer) + multiwr := multipart.NewWriter(body) + multiwr.SetBoundary("------------------------f77f80a7092eb312") + pw, _ := multiwr.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json"}, "Content-Disposition": {"form-data; name=metadata"}}) + pw.Write([]byte(testCase.metadata)) + pw, _ = multiwr.CreateFormFile("file", "kubeconfig") + pw.Write([]byte(testCase.kubeconfig)) + multiwr.Close() + + request := httptest.NewRequest("POST", "/v2/cluster-providers/clusterProvider1/clusters", bytes.NewBuffer(body.Bytes())) + request.Header.Set("Content-Type", multiwr.FormDataContentType()) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusCreated + if resp.StatusCode == http.StatusCreated { + got := moduleLib.Cluster{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("createHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterGetAllHandler(t *testing.T) { + + testCases := []struct { + label string + expected []moduleLib.Cluster + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Clusters", + expectedCode: http.StatusOK, + expected: []moduleLib.Cluster{ + { + Metadata: moduleLib.Metadata{ + Name: "testCluster1", + Description: "testCluster 1 description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "testCluster2", + Description: "testCluster 2 description", + UserData1: "some user data A", + UserData2: "some user data B", + }, + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterItems: []moduleLib.Cluster{ + { + Metadata: moduleLib.Metadata{ + Name: "testCluster1", + Description: "testCluster 1 description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "testCluster2", + Description: "testCluster 2 description", + UserData1: "some user data A", + UserData2: "some user data B", + }, + }, + }, + ClusterContentItems: []moduleLib.ClusterContent{ + // content here doesn't matter - just needs to be present + { + Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", + }, + { + Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvder1/clusters", nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := []moduleLib.Cluster{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterGetHandler(t *testing.T) { + + testCases := []struct { + label string + expected moduleLib.Cluster + name, version string + accept string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster with Accept: application/json", + accept: "application/json", + expectedCode: http.StatusOK, + expected: moduleLib.Cluster{ + Metadata: moduleLib.Metadata{ + Name: "testCluster", + Description: "testCluster description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + name: "testCluster", + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterItems: []moduleLib.Cluster{ + { + Metadata: moduleLib.Metadata{ + Name: "testCluster", + Description: "testCluster description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + ClusterContentItems: []moduleLib.ClusterContent{ + { + Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", + }, + }, + }, + }, + { + label: "Get Non-Existing Cluster", + accept: "application/json", + expectedCode: http.StatusInternalServerError, + name: "nonexistingcluster", + clusterClient: &mockClusterManager{ + ClusterItems: []moduleLib.Cluster{}, + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) + if len(testCase.accept) > 0 { + request.Header.Set("Accept", testCase.accept) + } + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := moduleLib.Cluster{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterGetContentHandler(t *testing.T) { + + testCases := []struct { + label string + expected string + name, version string + accept string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster Content with Accept: application/octet-stream", + accept: "application/octet-stream", + expectedCode: http.StatusOK, + expected: `test contents +of a file attached +to the creation +of clusterTest +`, + name: "testCluster", + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterItems: []moduleLib.Cluster{ + { + Metadata: moduleLib.Metadata{ + Name: "testCluster", + Description: "testCluster description", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + }, + }, + ClusterContentItems: []moduleLib.ClusterContent{ + { + Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", + }, + }, + }, + }, + { + label: "Get Non-Existing Cluster", + accept: "application/octet-stream", + expectedCode: http.StatusInternalServerError, + name: "nonexistingcluster", + clusterClient: &mockClusterManager{ + ClusterItems: []moduleLib.Cluster{}, + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) + if len(testCase.accept) > 0 { + request.Header.Set("Accept", testCase.accept) + } + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + body := new(bytes.Buffer) + body.ReadFrom(resp.Body) + got := body.String() + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterDeleteHandler(t *testing.T) { + + testCases := []struct { + label string + name string + version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Delete Cluster", + expectedCode: http.StatusNoContent, + name: "testCluster", + clusterClient: &mockClusterManager{}, + }, + { + label: "Delete Non-Existing Cluster", + expectedCode: http.StatusInternalServerError, + name: "testCluster", + clusterClient: &mockClusterManager{ + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("DELETE", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + }) + } +} + +func TestClusterLabelCreateHandler(t *testing.T) { + testCases := []struct { + label string + reader io.Reader + expected moduleLib.ClusterLabel + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Missing Cluster Label Body Failure", + expectedCode: http.StatusBadRequest, + clusterClient: &mockClusterManager{}, + }, + { + label: "Create Cluster Label", + expectedCode: http.StatusCreated, + reader: bytes.NewBuffer([]byte(`{ + "label-name": "test-label" + }`)), + expected: moduleLib.ClusterLabel{ + LabelName: "test-label", + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterLabelItems: []moduleLib.ClusterLabel{ + { + LabelName: "test-label", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/labels", testCase.reader) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusCreated + if resp.StatusCode == http.StatusCreated { + got := moduleLib.ClusterLabel{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("createHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterLabelsGetHandler(t *testing.T) { + + testCases := []struct { + label string + expected []moduleLib.ClusterLabel + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster Labels", + expectedCode: http.StatusOK, + expected: []moduleLib.ClusterLabel{ + { + LabelName: "test-label1", + }, + { + LabelName: "test-label-two", + }, + { + LabelName: "test-label-3", + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterLabelItems: []moduleLib.ClusterLabel{ + { + LabelName: "test-label1", + }, + { + LabelName: "test-label-two", + }, + { + LabelName: "test-label-3", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/labels", nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := []moduleLib.ClusterLabel{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterLabelGetHandler(t *testing.T) { + + testCases := []struct { + label string + expected moduleLib.ClusterLabel + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster Label", + expectedCode: http.StatusOK, + expected: moduleLib.ClusterLabel{ + LabelName: "testlabel", + }, + name: "testlabel", + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterLabelItems: []moduleLib.ClusterLabel{ + { + LabelName: "testlabel", + }, + }, + }, + }, + { + label: "Get Non-Existing Cluster Label", + expectedCode: http.StatusInternalServerError, + name: "nonexistingclusterlabel", + clusterClient: &mockClusterManager{ + ClusterLabelItems: []moduleLib.ClusterLabel{}, + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/labels/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := moduleLib.ClusterLabel{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterLabelDeleteHandler(t *testing.T) { + + testCases := []struct { + label string + name string + version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Delete Cluster Label", + expectedCode: http.StatusNoContent, + name: "testClusterLabel", + clusterClient: &mockClusterManager{}, + }, + { + label: "Delete Non-Existing Cluster Label", + expectedCode: http.StatusInternalServerError, + name: "testClusterLabel", + clusterClient: &mockClusterManager{ + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/labels/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + }) + } +} + +func TestClusterKvPairsCreateHandler(t *testing.T) { + testCases := []struct { + label string + reader io.Reader + expected moduleLib.ClusterKvPairs + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Missing Cluster KvPairs Body Failure", + expectedCode: http.StatusBadRequest, + clusterClient: &mockClusterManager{}, + }, + { + label: "Create Cluster KvPairs", + expectedCode: http.StatusCreated, + reader: bytes.NewBuffer([]byte(`{ + "metadata": { + "name": "ClusterKvPair1", + "description": "test cluster kv pairs", + "userData1": "some user data 1", + "userData2": "some user data 2" + }, + "spec": { + "kv": [ + { + "key1": "value1" + }, + { + "key2": "value2" + } + ] + } + }`)), + expected: moduleLib.ClusterKvPairs{ + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair1", + Description: "test cluster kv pairs", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "key1": "value1", + }, + { + "key2": "value2", + }, + }, + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair1", + Description: "test cluster kv pairs", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "key1": "value1", + }, + { + "key2": "value2", + }, + }, + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", testCase.reader) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusCreated + if resp.StatusCode == http.StatusCreated { + got := moduleLib.ClusterKvPairs{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("createHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterKvPairsGetAllHandler(t *testing.T) { + + testCases := []struct { + label string + expected []moduleLib.ClusterKvPairs + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster KvPairs", + expectedCode: http.StatusOK, + expected: []moduleLib.ClusterKvPairs{ + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair1", + Description: "test cluster kv pairs", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "key1": "value1", + }, + { + "key2": "value2", + }, + }, + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair2", + Description: "test cluster kv pairs", + UserData1: "some user data A", + UserData2: "some user data B", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "keyA": "valueA", + }, + { + "keyB": "valueB", + }, + }, + }, + }, + }, + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair1", + Description: "test cluster kv pairs", + UserData1: "some user data 1", + UserData2: "some user data 2", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "key1": "value1", + }, + { + "key2": "value2", + }, + }, + }, + }, + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair2", + Description: "test cluster kv pairs", + UserData1: "some user data A", + UserData2: "some user data B", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "keyA": "valueA", + }, + { + "keyB": "valueB", + }, + }, + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := []moduleLib.ClusterKvPairs{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterKvPairsGetHandler(t *testing.T) { + + testCases := []struct { + label string + expected moduleLib.ClusterKvPairs + name, version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Get Cluster KV Pairs", + expectedCode: http.StatusOK, + expected: moduleLib.ClusterKvPairs{ + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair2", + Description: "test cluster kv pairs", + UserData1: "some user data A", + UserData2: "some user data B", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "keyA": "valueA", + }, + { + "keyB": "valueB", + }, + }, + }, + }, + name: "ClusterKvPair2", + clusterClient: &mockClusterManager{ + //Items that will be returned by the mocked Client + ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ + { + Metadata: moduleLib.Metadata{ + Name: "ClusterKvPair2", + Description: "test cluster kv pairs", + UserData1: "some user data A", + UserData2: "some user data B", + }, + Spec: moduleLib.ClusterKvSpec{ + Kv: []map[string]interface{}{ + { + "keyA": "valueA", + }, + { + "keyB": "valueB", + }, + }, + }, + }, + }, + }, + }, + { + label: "Get Non-Existing Cluster KV Pairs", + expectedCode: http.StatusInternalServerError, + name: "nonexistingclusterkvpairs", + clusterClient: &mockClusterManager{ + ClusterKvPairsItems: []moduleLib.ClusterKvPairs{}, + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/kv-pairs/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + + //Check returned body only if statusOK + if resp.StatusCode == http.StatusOK { + got := moduleLib.ClusterKvPairs{} + json.NewDecoder(resp.Body).Decode(&got) + + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("listHandler returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestClusterKvPairsDeleteHandler(t *testing.T) { + + testCases := []struct { + label string + name string + version string + expectedCode int + clusterClient *mockClusterManager + }{ + { + label: "Delete Cluster KV Pairs", + expectedCode: http.StatusNoContent, + name: "testClusterKvPairs", + clusterClient: &mockClusterManager{}, + }, + { + label: "Delete Non-Existing Cluster KV Pairs", + expectedCode: http.StatusInternalServerError, + name: "testClusterKvPairs", + clusterClient: &mockClusterManager{ + Err: pkgerrors.New("Internal Error"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs/"+testCase.name, nil) + resp := executeRequest(request, NewRouter(testCase.clusterClient)) + + //Check returned code + if resp.StatusCode != testCase.expectedCode { + t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) + } + }) + } +} diff --git a/src/ncm/api/testing.go b/src/ncm/api/testing.go new file mode 100644 index 00000000..fed5c080 --- /dev/null +++ b/src/ncm/api/testing.go @@ -0,0 +1,31 @@ +/* + * 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 ( + "net/http" + "net/http/httptest" + + "github.com/gorilla/mux" +) + +func executeRequest(request *http.Request, router *mux.Router) *http.Response { + recorder := httptest.NewRecorder() + router.ServeHTTP(recorder, request) + resp := recorder.Result() + return resp +} diff --git a/src/ncm/cmd/main.go b/src/ncm/cmd/main.go new file mode 100644 index 00000000..c4ae423f --- /dev/null +++ b/src/ncm/cmd/main.go @@ -0,0 +1,77 @@ +/* +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" + "log" + "math/rand" + "net/http" + "os" + "os/signal" + "time" + + "github.com/gorilla/handlers" + "github.com/onap/multicloud-k8s/src/ncm/api" + "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" +) + +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, + } + + 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/ncm/go.mod b/src/ncm/go.mod new file mode 100644 index 00000000..32ff481a --- /dev/null +++ b/src/ncm/go.mod @@ -0,0 +1,31 @@ +module github.com/onap/multicloud-k8s/src/ncm + +require ( + github.com/coreos/etcd v3.3.12+incompatible + github.com/docker/engine v0.0.0-20190620014054-c513a4c6c298 + github.com/ghodss/yaml v1.0.0 + github.com/gorilla/handlers v1.3.0 + github.com/gorilla/mux v1.6.2 + github.com/hashicorp/consul v1.4.0 + github.com/pkg/errors v0.8.1 + github.com/sirupsen/logrus v1.4.2 + go.etcd.io/etcd v3.3.12+incompatible + go.mongodb.org/mongo-driver v1.0.0 + golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 + 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/helm v2.14.3+incompatible +) + +replace ( + 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/ncm/pkg/module/cluster.go b/src/ncm/pkg/module/cluster.go new file mode 100644 index 00000000..c9ddad6e --- /dev/null +++ b/src/ncm/pkg/module/cluster.go @@ -0,0 +1,540 @@ +/* + * 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" +) + +// ClusterProvider contains the parameters needed for ClusterProviders +// It implements the interface for managing the ClusterProviders +type Metadata struct { + Name string `json:"name"` + Description string `json:"description"` + UserData1 string `json:"userData1"` + UserData2 string `json:"userData2"` +} + +type ClusterProvider struct { + Metadata Metadata `json:"metadata"` +} + +type Cluster struct { + Metadata Metadata `json:"metadata"` +} + +type ClusterContent struct { + Kubeconfig string `json:"kubeconfig"` +} + +type ClusterLabel struct { + LabelName string `json:"label-name"` +} + +type ClusterKvPairs struct { + Metadata Metadata `json:"metadata"` + Spec ClusterKvSpec `json:"spec"` +} + +type ClusterKvSpec struct { + Kv []map[string]interface{} `json:"kv"` +} + +// ClusterProviderKey is the key structure that is used in the database +type ClusterProviderKey struct { + ClusterProviderName string `json:"provider"` +} + +// ClusterKey is the key structure that is used in the database +type ClusterKey struct { + ClusterProviderName string `json:"provider"` + ClusterName string `json:"cluster"` +} + +// ClusterLabelKey is the key structure that is used in the database +type ClusterLabelKey struct { + ClusterProviderName string `json:"provider"` + ClusterName string `json:"cluster"` + ClusterLabelName string `json:"label"` +} + +// ClusterKvPairsKey is the key structure that is used in the database +type ClusterKvPairsKey struct { + ClusterProviderName string `json:"provider"` + ClusterName string `json:"cluster"` + ClusterKvPairsName string `json:"kvname"` +} + +// Manager is an interface exposes the Cluster functionality +type ClusterManager interface { + CreateClusterProvider(pr ClusterProvider) (ClusterProvider, error) + GetClusterProvider(name string) (ClusterProvider, error) + GetClusterProviders() ([]ClusterProvider, error) + DeleteClusterProvider(name string) error + CreateCluster(provider string, pr Cluster, qr ClusterContent) (Cluster, error) + GetCluster(provider, name string) (Cluster, error) + GetClusterContent(provider, name string) (ClusterContent, error) + GetClusters(provider string) ([]Cluster, error) + DeleteCluster(provider, name string) error + CreateClusterLabel(provider, cluster string, pr ClusterLabel) (ClusterLabel, error) + GetClusterLabel(provider, cluster, label string) (ClusterLabel, error) + GetClusterLabels(provider, cluster string) ([]ClusterLabel, error) + DeleteClusterLabel(provider, cluster, label string) error + CreateClusterKvPairs(provider, cluster string, pr ClusterKvPairs) (ClusterKvPairs, error) + GetClusterKvPairs(provider, cluster, kvpair string) (ClusterKvPairs, error) + GetAllClusterKvPairs(provider, cluster string) ([]ClusterKvPairs, error) + DeleteClusterKvPairs(provider, cluster, kvpair string) error +} + +// ClusterClient implements the Manager +// It will also be used to maintain some localized state +type ClusterClient struct { + storeName string + tagMeta string + tagContent string +} + +// NewClusterClient returns an instance of the ClusterClient +// which implements the Manager +func NewClusterClient() *ClusterClient { + return &ClusterClient{ + storeName: "cluster", + tagMeta: "clustermetadata", + tagContent: "clustercontent", + } +} + +// CreateClusterProvider - create a new Cluster Provider +func (v *ClusterClient) CreateClusterProvider(p ClusterProvider) (ClusterProvider, error) { + + //Construct key and tag to select the entry + key := ClusterProviderKey{ + ClusterProviderName: p.Metadata.Name, + } + + //Check if this ClusterProvider already exists + _, err := v.GetClusterProvider(p.Metadata.Name) + if err == nil { + return ClusterProvider{}, pkgerrors.New("ClusterProvider already exists") + } + + err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) + if err != nil { + return ClusterProvider{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return p, nil +} + +// GetClusterProvider returns the ClusterProvider for corresponding name +func (v *ClusterClient) GetClusterProvider(name string) (ClusterProvider, error) { + + //Construct key and tag to select the entry + key := ClusterProviderKey{ + ClusterProviderName: name, + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return ClusterProvider{}, pkgerrors.Wrap(err, "Get ClusterProvider") + } + + //value is a byte array + if value != nil { + cp := ClusterProvider{} + err = db.DBconn.Unmarshal(value[0], &cp) + if err != nil { + return ClusterProvider{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return cp, nil + } + + return ClusterProvider{}, pkgerrors.New("Error getting ClusterProvider") +} + +// GetClusterProviderList returns all of the ClusterProvider for corresponding name +func (v *ClusterClient) GetClusterProviders() ([]ClusterProvider, error) { + + //Construct key and tag to select the entry + key := ClusterProviderKey{ + ClusterProviderName: "", + } + + var resp []ClusterProvider + values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return []ClusterProvider{}, pkgerrors.Wrap(err, "Get ClusterProviders") + } + + for _, value := range values { + cp := ClusterProvider{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []ClusterProvider{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// DeleteClusterProvider the ClusterProvider from database +func (v *ClusterClient) DeleteClusterProvider(name string) error { + + //Construct key and tag to select the entry + key := ClusterProviderKey{ + ClusterProviderName: name, + } + + err := db.DBconn.Remove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete ClusterProvider Entry;") + } + + return nil +} + +// CreateCluster - create a new Cluster for a cluster-provider +func (v *ClusterClient) CreateCluster(provider string, p Cluster, q ClusterContent) (Cluster, error) { + + //Construct key and tag to select the entry + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: p.Metadata.Name, + } + + //Verify ClusterProvider already exists + _, err := v.GetClusterProvider(provider) + if err != nil { + return Cluster{}, pkgerrors.New("ClusterProvider does not exist") + } + + //Check if this Cluster already exists + _, err = v.GetCluster(provider, p.Metadata.Name) + if err == nil { + return Cluster{}, pkgerrors.New("Cluster already exists") + } + + err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) + if err != nil { + return Cluster{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + err = db.DBconn.Insert(v.storeName, key, nil, v.tagContent, q) + if err != nil { + return Cluster{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return p, nil +} + +// GetCluster returns the Cluster for corresponding provider and name +func (v *ClusterClient) GetCluster(provider, name string) (Cluster, error) { + //Construct key and tag to select the entry + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: name, + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return Cluster{}, pkgerrors.Wrap(err, "Get Cluster") + } + + //value is a byte array + if value != nil { + cl := Cluster{} + err = db.DBconn.Unmarshal(value[0], &cl) + if err != nil { + return Cluster{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return cl, nil + } + + return Cluster{}, pkgerrors.New("Error getting Cluster") +} + +// GetClusterContent returns the ClusterContent for corresponding provider and name +func (v *ClusterClient) GetClusterContent(provider, name string) (ClusterContent, error) { + //Construct key and tag to select the entry + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: name, + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagContent) + if err != nil { + return ClusterContent{}, pkgerrors.Wrap(err, "Get Cluster Content") + } + + //value is a byte array + if value != nil { + cc := ClusterContent{} + err = db.DBconn.Unmarshal(value[0], &cc) + if err != nil { + return ClusterContent{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return cc, nil + } + + return ClusterContent{}, pkgerrors.New("Error getting Cluster Content") +} + +// GetClusters returns all the Clusters for corresponding provider +func (v *ClusterClient) GetClusters(provider string) ([]Cluster, error) { + //Construct key and tag to select the entry + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: "", + } + + values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return []Cluster{}, pkgerrors.Wrap(err, "Get Clusters") + } + + var resp []Cluster + + for _, value := range values { + cp := Cluster{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []Cluster{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// DeleteCluster the Cluster from database +func (v *ClusterClient) DeleteCluster(provider, name string) error { + //Construct key and tag to select the entry + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: name, + } + + err := db.DBconn.Remove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete Cluster Entry;") + } + + return nil +} + +// CreateClusterLabel - create a new Cluster Label mongo document for a cluster-provider/cluster +func (v *ClusterClient) CreateClusterLabel(provider string, cluster string, p ClusterLabel) (ClusterLabel, error) { + //Construct key and tag to select the entry + key := ClusterLabelKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterLabelName: p.LabelName, + } + + //Verify Cluster already exists + _, err := v.GetCluster(provider, cluster) + if err != nil { + return ClusterLabel{}, pkgerrors.New("Cluster does not exist") + } + + //Check if this ClusterLabel already exists + _, err = v.GetClusterLabel(provider, cluster, p.LabelName) + if err == nil { + return ClusterLabel{}, pkgerrors.New("Cluster Label already exists") + } + + err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) + if err != nil { + return ClusterLabel{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return p, nil +} + +// GetClusterLabel returns the Cluster for corresponding provider, cluster and label +func (v *ClusterClient) GetClusterLabel(provider, cluster, label string) (ClusterLabel, error) { + //Construct key and tag to select the entry + key := ClusterLabelKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterLabelName: label, + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return ClusterLabel{}, pkgerrors.Wrap(err, "Get Cluster") + } + + //value is a byte array + if value != nil { + cl := ClusterLabel{} + err = db.DBconn.Unmarshal(value[0], &cl) + if err != nil { + return ClusterLabel{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return cl, nil + } + + return ClusterLabel{}, pkgerrors.New("Error getting Cluster") +} + +// GetClusterLabels returns the Cluster Labels for corresponding provider and cluster +func (v *ClusterClient) GetClusterLabels(provider, cluster string) ([]ClusterLabel, error) { + //Construct key and tag to select the entry + key := ClusterLabelKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterLabelName: "", + } + + values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return []ClusterLabel{}, pkgerrors.Wrap(err, "Get Cluster Labels") + } + + var resp []ClusterLabel + + for _, value := range values { + cp := ClusterLabel{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []ClusterLabel{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// Delete the Cluster Label from database +func (v *ClusterClient) DeleteClusterLabel(provider, cluster, label string) error { + //Construct key and tag to select the entry + key := ClusterLabelKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterLabelName: label, + } + + err := db.DBconn.Remove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete ClusterLabel Entry;") + } + + return nil +} + +// CreateClusterKvPairs - Create a New Cluster KV pairs document +func (v *ClusterClient) CreateClusterKvPairs(provider string, cluster string, p ClusterKvPairs) (ClusterKvPairs, error) { + key := ClusterKvPairsKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterKvPairsName: p.Metadata.Name, + } + + //Verify Cluster already exists + _, err := v.GetCluster(provider, cluster) + if err != nil { + return ClusterKvPairs{}, pkgerrors.New("Cluster does not exist") + } + + //Check if this ClusterKvPairs already exists + _, err = v.GetClusterKvPairs(provider, cluster, p.Metadata.Name) + if err == nil { + return ClusterKvPairs{}, pkgerrors.New("Cluster KV Pair already exists") + } + + err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) + if err != nil { + return ClusterKvPairs{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return p, nil +} + +// GetClusterKvPairs returns the Cluster KeyValue pair for corresponding provider, cluster and KV pair name +func (v *ClusterClient) GetClusterKvPairs(provider, cluster, kvpair string) (ClusterKvPairs, error) { + //Construct key and tag to select entry + key := ClusterKvPairsKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterKvPairsName: kvpair, + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return ClusterKvPairs{}, pkgerrors.Wrap(err, "Get Cluster") + } + + //value is a byte array + if value != nil { + ckvp := ClusterKvPairs{} + err = db.DBconn.Unmarshal(value[0], &ckvp) + if err != nil { + return ClusterKvPairs{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return ckvp, nil + } + + return ClusterKvPairs{}, pkgerrors.New("Error getting Cluster") +} + +// GetAllClusterKvPairs returns the Cluster Kv Pairs for corresponding provider and cluster +func (v *ClusterClient) GetAllClusterKvPairs(provider, cluster string) ([]ClusterKvPairs, error) { + //Construct key and tag to select the entry + key := ClusterKvPairsKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterKvPairsName: "", + } + + values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) + if err != nil { + return []ClusterKvPairs{}, pkgerrors.Wrap(err, "Get Cluster KV Pairs") + } + + var resp []ClusterKvPairs + + for _, value := range values { + cp := ClusterKvPairs{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []ClusterKvPairs{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// DeleteClusterKvPairs the ClusterKvPairs from database +func (v *ClusterClient) DeleteClusterKvPairs(provider, cluster, kvpair string) error { + //Construct key and tag to select entry + key := ClusterKvPairsKey{ + ClusterProviderName: provider, + ClusterName: cluster, + ClusterKvPairsName: kvpair, + } + + err := db.DBconn.Remove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete ClusterKvPairs Entry;") + } + + return nil +} diff --git a/src/ncm/pkg/module/module.go b/src/ncm/pkg/module/module.go new file mode 100644 index 00000000..c1c24510 --- /dev/null +++ b/src/ncm/pkg/module/module.go @@ -0,0 +1,31 @@ +/* + * 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 orchestrator +type Client struct { + Cluster *ClusterClient + // Add Clients for API's here +} + +// NewClient creates a new client for using the services +func NewClient() *Client { + c := &Client{} + c.Cluster = NewClusterClient() + // Add Client API handlers here + return c +} diff --git a/src/ncm/scripts/Dockerfile b/src/ncm/scripts/Dockerfile new file mode 100644 index 00000000..d1b58677 --- /dev/null +++ b/src/ncm/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/ncm +RUN chown onap:onap /opt/multicloud/k8s/ncm -R + +ADD --chown=onap ./ncm ./ + +USER onap + +CMD ["./ncm"] diff --git a/src/ncm/tests/certs/auth_test_certificate.pem b/src/ncm/tests/certs/auth_test_certificate.pem new file mode 100644 index 00000000..42e77491 --- /dev/null +++ b/src/ncm/tests/certs/auth_test_certificate.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAKAHJi8eUs73MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgwNTE1MDQ0MDQwWhcNMTkwNTE1MDQ0MDQwWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA5PHDk+RRFh5o3Xe2nZuLn0Vo+5BjnHp/ul2NNYSG00Slc8F86gW4xcNA +wm6xC8tYCSangV2lFG3E8H2L7SCEVaM5VDV2GCOpOoMihc+2Qenk/YbHwuYenwjo +OgTK4aCItqjcAJ2DB1KC7AxARxHBDu9Kif+M/pc49so+G9ObQuS8k2vmTTaRYkMK +ZvbTJcWsc0vbNnPhxcG5PVj4unlaREM+yQDm18/glUkkBNnYKMHABRvPnBrDktTT +BQWsqkbQTw7ZuLOrl9rCzVTstZX9wEXarrstIdQJj3KZjbFOp2opND8bjNIjcdVt +iRFnP1nHQYr7EgRqcx/YMJZ+gmCy3wIDAQABo1AwTjAdBgNVHQ4EFgQU9qPNwwIu +kZh41sJqFtnMC2blSYMwHwYDVR0jBBgwFoAU9qPNwwIukZh41sJqFtnMC2blSYMw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA4+daLY1wE10IMPaOKurG +QBvfYeO/rgNXGeg0TisTIKAfx/We9Hmwo/37Bd2Nk5gxfy/DIJ4lMbrzXjgWITlm +XOrS5QfluwvaEcREtHFtPFa3NZqn2VzKNDFTR+rJj7I5o600NKdcPrGeQ1i/vny2 +K0g68ogw2jfufcuePvZTYGst8RclomPr7ZXxI24kIjcE1MbiViy68sQueTXBEr5s +Th6RsvPfVnLxjR/m/V6VJl31nn4T6hbmKzXCHo/X7aC3I8Isui4bQGKgfAxyBkhE +0T7tP+GgymiEKQ6qJ/1c4HFFSuFRUQjLnK7uJu9jM/HMKoLCPayx6birHZRIMF94 +pg== +-----END CERTIFICATE----- diff --git a/src/ncm/tests/certs/auth_test_key.pem b/src/ncm/tests/certs/auth_test_key.pem new file mode 100644 index 00000000..5f01f572 --- /dev/null +++ b/src/ncm/tests/certs/auth_test_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDk8cOT5FEWHmjd +d7adm4ufRWj7kGOcen+6XY01hIbTRKVzwXzqBbjFw0DCbrELy1gJJqeBXaUUbcTw +fYvtIIRVozlUNXYYI6k6gyKFz7ZB6eT9hsfC5h6fCOg6BMrhoIi2qNwAnYMHUoLs +DEBHEcEO70qJ/4z+lzj2yj4b05tC5LyTa+ZNNpFiQwpm9tMlxaxzS9s2c+HFwbk9 +WPi6eVpEQz7JAObXz+CVSSQE2dgowcAFG8+cGsOS1NMFBayqRtBPDtm4s6uX2sLN +VOy1lf3ARdquuy0h1AmPcpmNsU6naik0PxuM0iNx1W2JEWc/WcdBivsSBGpzH9gw +ln6CYLLfAgMBAAECggEAYB3H2D0QddLKf8AUoNJ+qZ1AV+zkhPtAyIMiF4fN+sBl +HdXrlWxViGFSvM4v8h2qlhzuUfd4qLz042ox5pmyNSnTlbDkJXpDP9dyFO+BOubx +Ribhksd9r5LTvBfq/RKikt0NkAyQx/AyGtuB2NRxUs3PY2QwU2o1dhauQIx0MH5/ +6D8PgQf6+5njKQaKa4e8Kp4kB+KjnALvt6JgYuNJUHWap+nnDbuuVy5dl1bKkAZ+ +qa7CITKWO4kE2EqaCb2asFc2w3538+w72UJZtwQCmOaxtKpRSl9fQXu54N8jIGoZ +1FvEj5x3X6QkglE+iVJYaX3RmiJ3uzZ2LICDr89vEQKBgQD7fquIw4p1idSxz3Cm +5o3Y5kD0CKm61ZaRJWKd+tNlSsxubmV9HROYW6vj2xEPSDvyp1na00pDXxMJQLLc +O5Awd1SaU+d45jnoi70fsEY8X0WH1rDTYfnU+zQBmpbGqX5qTIfpy4yoADiUD1CQ +EBdaSBWiKPx2jFSct58TwDP9YwKBgQDpC64TScZYz7uQq4gAbDso/7TjNwgt/Bw8 +JgLSdx1UdUclh81smTujsouyCFwJSvRjKik8e/Qt0f5patukFbFRINxUGUDhOKbA +7zqeNQbeYaP7Rvw+3z01CU2BTBmB/EWa2xWDam8B9xQvjiHSOrubqkt3sIQJb045 +hzuigdV7VQKBgQD7Gnd0nyCwyMSIIMGuswYv6X4y6i9lr3qdQ4GakOTe/vbsz+cf +K5f0CJuwbnszEgFg/zzVIx/D8rqUA3hSMlp+ObdMO7gi22Q4TsWvTRZjkxBeV7rH +48xJneNIMqyWgIcK5YzSn3y6BTZ4hm3+2UInz09iUJ/6UZTtwNzhIIgIVwKBgQCT +LxRHDE4gIzrT+PHRSonmr/DfnA8nc9WlS2B26lH02IkRs/5Su0iGb6p4y3zNRbCp +vKQElki2c60ZiSqlLCosEfP1jWmDlRMEQVMlPlpTMxmtBr0jPDzc9T4lDhoCFYEk +d3/T2vG3LQRrsHm92+hHPTuioTIS/2BJRxar4RIibQKBgQC8zoayoQ7zfEYxy3Ax +OSao8g85hj0EAJk/VKQP2POgz6KoPay3JE9D7P7OvkebTyv/pijAuTPby4XipCNI +K0JbFC2Kn7RW/ZV23UdnoO9crh2omOh+/52prStWXKoc+/pJe70Af+4rU7FUiI7F +y1mIE9krIoVis6iYsyFEmkP7iw== +-----END PRIVATE KEY----- diff --git a/src/ncm/tests/configs/mock_config.json b/src/ncm/tests/configs/mock_config.json new file mode 100644 index 00000000..47a6b627 --- /dev/null +++ b/src/ncm/tests/configs/mock_config.json @@ -0,0 +1,5 @@ +{ + "database-type": "mock_db_test", + "database-ip": "127.0.0.1", + "plugin-dir": "." +} \ No newline at end of file diff --git a/src/orchestrator/api/api.go b/src/orchestrator/api/api.go index a261319c..1d38f106 100644 --- a/src/orchestrator/api/api.go +++ b/src/orchestrator/api/api.go @@ -28,7 +28,6 @@ func NewRouter(projectClient moduleLib.ProjectManager, compositeAppClient moduleLib.CompositeAppManager, appClient moduleLib.AppManager, ControllerClient moduleLib.ControllerManager, - clusterClient moduleLib.ClusterManager, genericPlacementIntentClient moduleLib.GenericPlacementIntentManager, appIntentClient moduleLib.AppIntentManager, deploymentIntentGrpClient moduleLib.DeploymentIntentGroupManager, @@ -54,12 +53,6 @@ func NewRouter(projectClient moduleLib.ProjectManager, controlHandler := controllerHandler{ client: ControllerClient, } - if clusterClient == nil { - clusterClient = moduleClient.Cluster - } - clusterHandler := clusterHandler{ - client: clusterClient, - } router.HandleFunc("/projects", projHandler.createHandler).Methods("POST") router.HandleFunc("/projects/{project-name}", projHandler.getHandler).Methods("GET") router.HandleFunc("/projects/{project-name}", projHandler.deleteHandler).Methods("DELETE") @@ -120,22 +113,6 @@ func NewRouter(projectClient moduleLib.ProjectManager, router.HandleFunc("/controllers", controlHandler.createHandler).Methods("PUT") router.HandleFunc("/controllers/{controller-name}", controlHandler.getHandler).Methods("GET") router.HandleFunc("/controllers/{controller-name}", controlHandler.deleteHandler).Methods("DELETE") - router.HandleFunc("/cluster-providers", clusterHandler.createClusterProviderHandler).Methods("POST") - router.HandleFunc("/cluster-providers", clusterHandler.getClusterProviderHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{name}", clusterHandler.getClusterProviderHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{name}", clusterHandler.deleteClusterProviderHandler).Methods("DELETE") - router.HandleFunc("/cluster-providers/{provider-name}/clusters", clusterHandler.createClusterHandler).Methods("POST") - router.HandleFunc("/cluster-providers/{provider-name}/clusters", clusterHandler.getClusterHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{name}", clusterHandler.getClusterHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{name}", clusterHandler.deleteClusterHandler).Methods("DELETE") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels", clusterHandler.createClusterLabelHandler).Methods("POST") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels", clusterHandler.getClusterLabelHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels/{label}", clusterHandler.getClusterLabelHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/labels/{label}", clusterHandler.deleteClusterLabelHandler).Methods("DELETE") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs", clusterHandler.createClusterKvPairsHandler).Methods("POST") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs", clusterHandler.getClusterKvPairsHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs/{kvpair}", clusterHandler.getClusterKvPairsHandler).Methods("GET") - router.HandleFunc("/cluster-providers/{provider-name}/clusters/{cluster-name}/kv-pairs/{kvpair}", clusterHandler.deleteClusterKvPairsHandler).Methods("DELETE") //setting routes for genericPlacementIntent if genericPlacementIntentClient == nil { genericPlacementIntentClient = moduleClient.GenericPlacementIntent diff --git a/src/orchestrator/api/clusterhandler.go b/src/orchestrator/api/clusterhandler.go deleted file mode 100644 index ac4191e1..00000000 --- a/src/orchestrator/api/clusterhandler.go +++ /dev/null @@ -1,468 +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 ( - "bytes" - "encoding/base64" - "encoding/json" - "io" - "io/ioutil" - "mime" - "mime/multipart" - "net/http" - "net/textproto" - - moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module" - - "github.com/gorilla/mux" -) - -// Used to store backend implementations objects -// Also simplifies mocking for unit testing purposes -type clusterHandler struct { - // Interface that implements Cluster operations - // We will set this variable with a mock interface for testing - client moduleLib.ClusterManager -} - -// Create handles creation of the ClusterProvider entry in the database -func (h clusterHandler) createClusterProviderHandler(w http.ResponseWriter, r *http.Request) { - var p moduleLib.ClusterProvider - - err := json.NewDecoder(r.Body).Decode(&p) - - 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 p.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - ret, err := h.client.CreateClusterProvider(p) - 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 ClusterProvider Name -// Returns a ClusterProvider -func (h clusterHandler) getClusterProviderHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - var ret interface{} - var err error - - if len(name) == 0 { - ret, err = h.client.GetClusterProviders() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetClusterProvider(name) - 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 ClusterProvider Name -func (h clusterHandler) deleteClusterProviderHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - - err := h.client.DeleteClusterProvider(name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} - -// Create handles creation of the Cluster entry in the database -func (h clusterHandler) createClusterHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - var p moduleLib.Cluster - var q moduleLib.ClusterContent - - // Implemenation using multipart form - // Review and enable/remove at a later date - // Set Max size to 16mb here - err := r.ParseMultipartForm(16777216) - if err != nil { - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - jsn := bytes.NewBuffer([]byte(r.FormValue("metadata"))) - err = json.NewDecoder(jsn).Decode(&p) - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - //Read the file section and ignore the header - file, _, err := r.FormFile("file") - if err != nil { - http.Error(w, "Unable to process file", http.StatusUnprocessableEntity) - return - } - - defer file.Close() - - //Convert the file content to base64 for storage - content, err := ioutil.ReadAll(file) - if err != nil { - http.Error(w, "Unable to read file", http.StatusUnprocessableEntity) - return - } - - q.Kubeconfig = base64.StdEncoding.EncodeToString(content) - - // Name is required. - if p.Metadata.Name == "" { - http.Error(w, "Missing name in POST request", http.StatusBadRequest) - return - } - - ret, err := h.client.CreateCluster(provider, p, q) - 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 Cluster Name -// Returns a Cluster -func (h clusterHandler) getClusterHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - name := vars["name"] - - // handle the get all clusters case - return a list of only the json parts - if len(name) == 0 { - var retList []moduleLib.Cluster - - ret, err := h.client.GetClusters(provider) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - for _, cl := range ret { - retList = append(retList, moduleLib.Cluster{Metadata: cl.Metadata}) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(retList) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - - accepted, _, err := mime.ParseMediaType(r.Header.Get("Accept")) - if err != nil { - http.Error(w, err.Error(), http.StatusNotAcceptable) - return - } - - retCluster, err := h.client.GetCluster(provider, name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - retKubeconfig, err := h.client.GetClusterContent(provider, name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - switch accepted { - case "multipart/form-data": - mpw := multipart.NewWriter(w) - w.Header().Set("Content-Type", mpw.FormDataContentType()) - w.WriteHeader(http.StatusOK) - pw, err := mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json"}, "Content-Disposition": {"form-data; name=metadata"}}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if err := json.NewEncoder(pw).Encode(retCluster); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - pw, err = mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"form-data; name=file; filename=kubeconfig"}}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - _, err = pw.Write(kcBytes) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - case "application/json": - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(retCluster) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - case "application/octet-stream": - w.Header().Set("Content-Type", "application/octet-stream") - w.WriteHeader(http.StatusOK) - kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - _, err = w.Write(kcBytes) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - default: - http.Error(w, "set Accept: multipart/form-data, application/json or application/octet-stream", http.StatusMultipleChoices) - return - } -} - -// Delete handles DELETE operations on a particular Cluster Name -func (h clusterHandler) deleteClusterHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - name := vars["name"] - - err := h.client.DeleteCluster(provider, name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} - -// Create handles creation of the ClusterLabel entry in the database -func (h clusterHandler) createClusterLabelHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - var p moduleLib.ClusterLabel - - err := json.NewDecoder(r.Body).Decode(&p) - - // LabelName is required. - if p.LabelName == "" { - http.Error(w, "Missing label name in POST request", http.StatusBadRequest) - return - } - - ret, err := h.client.CreateClusterLabel(provider, cluster, p) - 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 Cluster Label -// Returns a ClusterLabel -func (h clusterHandler) getClusterLabelHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - label := vars["label"] - - var ret interface{} - var err error - - if len(label) == 0 { - ret, err = h.client.GetClusterLabels(provider, cluster) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetClusterLabel(provider, cluster, label) - 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 ClusterLabel Name -func (h clusterHandler) deleteClusterLabelHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - label := vars["label"] - - err := h.client.DeleteClusterLabel(provider, cluster, label) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} - -// Create handles creation of the ClusterKvPairs entry in the database -func (h clusterHandler) createClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - var p moduleLib.ClusterKvPairs - - err := json.NewDecoder(r.Body).Decode(&p) - - // KvPairsName is required. - if p.Metadata.Name == "" { - http.Error(w, "Missing Key Value pair name in POST request", http.StatusBadRequest) - return - } - - ret, err := h.client.CreateClusterKvPairs(provider, cluster, p) - 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 Cluster Key Value Pair -// Returns a ClusterKvPairs -func (h clusterHandler) getClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - kvpair := vars["kvpair"] - - var ret interface{} - var err error - - if len(kvpair) == 0 { - ret, err = h.client.GetAllClusterKvPairs(provider, cluster) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetClusterKvPairs(provider, cluster, kvpair) - 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 Cluster Name -func (h clusterHandler) deleteClusterKvPairsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - provider := vars["provider-name"] - cluster := vars["cluster-name"] - kvpair := vars["kvpair"] - - err := h.client.DeleteClusterKvPairs(provider, cluster, kvpair) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/src/orchestrator/api/clusterhandler_test.go b/src/orchestrator/api/clusterhandler_test.go deleted file mode 100644 index e5161a42..00000000 --- a/src/orchestrator/api/clusterhandler_test.go +++ /dev/null @@ -1,1412 +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 ( - "bytes" - "encoding/json" - "io" - "mime/multipart" - "net/http" - "net/http/httptest" - "net/textproto" - "reflect" - "testing" - - moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module" - - pkgerrors "github.com/pkg/errors" -) - -//Creating an embedded interface via anonymous variable -//This allows us to make mockDB satisfy the DatabaseConnection -//interface even if we are not implementing all the methods in it -type mockClusterManager struct { - // Items and err will be used to customize each test - // via a localized instantiation of mockClusterManager - ClusterProviderItems []moduleLib.ClusterProvider - ClusterItems []moduleLib.Cluster - ClusterContentItems []moduleLib.ClusterContent - ClusterLabelItems []moduleLib.ClusterLabel - ClusterKvPairsItems []moduleLib.ClusterKvPairs - Err error -} - -func (m *mockClusterManager) CreateClusterProvider(inp moduleLib.ClusterProvider) (moduleLib.ClusterProvider, error) { - if m.Err != nil { - return moduleLib.ClusterProvider{}, m.Err - } - - return m.ClusterProviderItems[0], nil -} - -func (m *mockClusterManager) GetClusterProvider(name string) (moduleLib.ClusterProvider, error) { - if m.Err != nil { - return moduleLib.ClusterProvider{}, m.Err - } - - return m.ClusterProviderItems[0], nil -} - -func (m *mockClusterManager) GetClusterProviders() ([]moduleLib.ClusterProvider, error) { - if m.Err != nil { - return []moduleLib.ClusterProvider{}, m.Err - } - - return m.ClusterProviderItems, nil -} - -func (m *mockClusterManager) DeleteClusterProvider(name string) error { - return m.Err -} - -func (m *mockClusterManager) CreateCluster(provider string, inp moduleLib.Cluster, inq moduleLib.ClusterContent) (moduleLib.Cluster, error) { - if m.Err != nil { - return moduleLib.Cluster{}, m.Err - } - - return m.ClusterItems[0], nil -} - -func (m *mockClusterManager) GetCluster(provider, name string) (moduleLib.Cluster, error) { - if m.Err != nil { - return moduleLib.Cluster{}, m.Err - } - - return m.ClusterItems[0], nil -} - -func (m *mockClusterManager) GetClusterContent(provider, name string) (moduleLib.ClusterContent, error) { - if m.Err != nil { - return moduleLib.ClusterContent{}, m.Err - } - - return m.ClusterContentItems[0], nil -} - -func (m *mockClusterManager) GetClusters(provider string) ([]moduleLib.Cluster, error) { - if m.Err != nil { - return []moduleLib.Cluster{}, m.Err - } - - return m.ClusterItems, nil -} - -func (m *mockClusterManager) DeleteCluster(provider, name string) error { - return m.Err -} - -func (m *mockClusterManager) CreateClusterLabel(provider, cluster string, inp moduleLib.ClusterLabel) (moduleLib.ClusterLabel, error) { - if m.Err != nil { - return moduleLib.ClusterLabel{}, m.Err - } - - return m.ClusterLabelItems[0], nil -} - -func (m *mockClusterManager) GetClusterLabel(provider, cluster, label string) (moduleLib.ClusterLabel, error) { - if m.Err != nil { - return moduleLib.ClusterLabel{}, m.Err - } - - return m.ClusterLabelItems[0], nil -} - -func (m *mockClusterManager) GetClusterLabels(provider, cluster string) ([]moduleLib.ClusterLabel, error) { - if m.Err != nil { - return []moduleLib.ClusterLabel{}, m.Err - } - - return m.ClusterLabelItems, nil -} - -func (m *mockClusterManager) DeleteClusterLabel(provider, cluster, label string) error { - return m.Err -} - -func (m *mockClusterManager) CreateClusterKvPairs(provider, cluster string, inp moduleLib.ClusterKvPairs) (moduleLib.ClusterKvPairs, error) { - if m.Err != nil { - return moduleLib.ClusterKvPairs{}, m.Err - } - - return m.ClusterKvPairsItems[0], nil -} - -func (m *mockClusterManager) GetClusterKvPairs(provider, cluster, kvpair string) (moduleLib.ClusterKvPairs, error) { - if m.Err != nil { - return moduleLib.ClusterKvPairs{}, m.Err - } - - return m.ClusterKvPairsItems[0], nil -} - -func (m *mockClusterManager) GetAllClusterKvPairs(provider, cluster string) ([]moduleLib.ClusterKvPairs, error) { - if m.Err != nil { - return []moduleLib.ClusterKvPairs{}, m.Err - } - - return m.ClusterKvPairsItems, nil -} - -func (m *mockClusterManager) DeleteClusterKvPairs(provider, cluster, kvpair string) error { - return m.Err -} - -func TestClusterProviderCreateHandler(t *testing.T) { - testCases := []struct { - label string - reader io.Reader - expected moduleLib.ClusterProvider - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Missing Cluster Provider Body Failure", - expectedCode: http.StatusBadRequest, - clusterClient: &mockClusterManager{}, - }, - { - label: "Create Cluster Provider", - expectedCode: http.StatusCreated, - reader: bytes.NewBuffer([]byte(`{ - "metadata": { - "name": "clusterProviderTest", - "description": "testClusterProvider", - "userData1": "some user data 1", - "userData2": "some user data 2" - } - }`)), - expected: moduleLib.ClusterProvider{ - Metadata: moduleLib.Metadata{ - Name: "clusterProviderTest", - Description: "testClusterProvider", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterProviderItems: []moduleLib.ClusterProvider{ - { - Metadata: moduleLib.Metadata{ - Name: "clusterProviderTest", - Description: "testClusterProvider", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - }, - }, - { - label: "Missing ClusterProvider Name in Request Body", - reader: bytes.NewBuffer([]byte(`{ - "metadata": { - "description": "this is a test cluster provider", - "userData1": "some user data 1", - "userData2": "some user data 2" - } - }`)), - expectedCode: http.StatusBadRequest, - clusterClient: &mockClusterManager{}, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("POST", "/v2/cluster-providers", testCase.reader) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusCreated - if resp.StatusCode == http.StatusCreated { - got := moduleLib.ClusterProvider{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("createHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterProviderGetAllHandler(t *testing.T) { - - testCases := []struct { - label string - expected []moduleLib.ClusterProvider - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster Provider", - expectedCode: http.StatusOK, - expected: []moduleLib.ClusterProvider{ - { - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider1", - Description: "testClusterProvider 1 description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider2", - Description: "testClusterProvider 2 description", - UserData1: "some user data A", - UserData2: "some user data B", - }, - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterProviderItems: []moduleLib.ClusterProvider{ - { - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider1", - Description: "testClusterProvider 1 description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider2", - Description: "testClusterProvider 2 description", - UserData1: "some user data A", - UserData2: "some user data B", - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers", nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := []moduleLib.ClusterProvider{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterProviderGetHandler(t *testing.T) { - - testCases := []struct { - label string - expected moduleLib.ClusterProvider - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster Provider", - expectedCode: http.StatusOK, - expected: moduleLib.ClusterProvider{ - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider", - Description: "testClusterProvider description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - name: "testClusterProvider", - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterProviderItems: []moduleLib.ClusterProvider{ - { - Metadata: moduleLib.Metadata{ - Name: "testClusterProvider", - Description: "testClusterProvider description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - }, - }, - { - label: "Get Non-Existing Cluster Provider", - expectedCode: http.StatusInternalServerError, - name: "nonexistingclusterprovider", - clusterClient: &mockClusterManager{ - ClusterProviderItems: []moduleLib.ClusterProvider{}, - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := moduleLib.ClusterProvider{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterProviderDeleteHandler(t *testing.T) { - - testCases := []struct { - label string - name string - version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Delete Cluster Provider", - expectedCode: http.StatusNoContent, - name: "testClusterProvider", - clusterClient: &mockClusterManager{}, - }, - { - label: "Delete Non-Existing Cluster Provider", - expectedCode: http.StatusInternalServerError, - name: "testClusterProvider", - clusterClient: &mockClusterManager{ - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("DELETE", "/v2/cluster-providers/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - }) - } -} - -func TestClusterCreateHandler(t *testing.T) { - testCases := []struct { - label string - metadata string - kubeconfig string - expected moduleLib.Cluster - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Missing Cluster Body Failure", - expectedCode: http.StatusBadRequest, - clusterClient: &mockClusterManager{}, - }, - { - label: "Create Cluster", - expectedCode: http.StatusCreated, - metadata: ` -{ - "metadata": { - "name": "clusterTest", - "description": "this is test cluster", - "userData1": "some cluster data abc", - "userData2": "some cluster data def" - } -}`, - kubeconfig: `test contents -of a file attached -to the creation -of clusterTest -`, - expected: moduleLib.Cluster{ - Metadata: moduleLib.Metadata{ - Name: "clusterTest", - Description: "testCluster", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterProviderItems: []moduleLib.ClusterProvider{ - { - Metadata: moduleLib.Metadata{ - Name: "clusterProvider1", - Description: "ClusterProvider 1 description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - ClusterItems: []moduleLib.Cluster{ - { - Metadata: moduleLib.Metadata{ - Name: "clusterTest", - Description: "testCluster", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - ClusterContentItems: []moduleLib.ClusterContent{ - { - Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", - }, - }, - }, - }, - { - label: "Missing Cluster Name in Request Body", - expectedCode: http.StatusBadRequest, - metadata: ` -{ - "metadata": { - "description": "this is test cluster", - "userData1": "some cluster data abc", - "userData2": "some cluster data def" - } -}`, - kubeconfig: `test contents -of a file attached -to the creation -of clusterTest -`, - clusterClient: &mockClusterManager{}, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - // Create the multipart test Request body - body := new(bytes.Buffer) - multiwr := multipart.NewWriter(body) - multiwr.SetBoundary("------------------------f77f80a7092eb312") - pw, _ := multiwr.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json"}, "Content-Disposition": {"form-data; name=metadata"}}) - pw.Write([]byte(testCase.metadata)) - pw, _ = multiwr.CreateFormFile("file", "kubeconfig") - pw.Write([]byte(testCase.kubeconfig)) - multiwr.Close() - - request := httptest.NewRequest("POST", "/v2/cluster-providers/clusterProvider1/clusters", bytes.NewBuffer(body.Bytes())) - request.Header.Set("Content-Type", multiwr.FormDataContentType()) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusCreated - if resp.StatusCode == http.StatusCreated { - got := moduleLib.Cluster{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("createHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterGetAllHandler(t *testing.T) { - - testCases := []struct { - label string - expected []moduleLib.Cluster - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Clusters", - expectedCode: http.StatusOK, - expected: []moduleLib.Cluster{ - { - Metadata: moduleLib.Metadata{ - Name: "testCluster1", - Description: "testCluster 1 description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "testCluster2", - Description: "testCluster 2 description", - UserData1: "some user data A", - UserData2: "some user data B", - }, - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterItems: []moduleLib.Cluster{ - { - Metadata: moduleLib.Metadata{ - Name: "testCluster1", - Description: "testCluster 1 description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "testCluster2", - Description: "testCluster 2 description", - UserData1: "some user data A", - UserData2: "some user data B", - }, - }, - }, - ClusterContentItems: []moduleLib.ClusterContent{ - // content here doesn't matter - just needs to be present - { - Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", - }, - { - Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvder1/clusters", nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := []moduleLib.Cluster{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterGetHandler(t *testing.T) { - - testCases := []struct { - label string - expected moduleLib.Cluster - name, version string - accept string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster with Accept: application/json", - accept: "application/json", - expectedCode: http.StatusOK, - expected: moduleLib.Cluster{ - Metadata: moduleLib.Metadata{ - Name: "testCluster", - Description: "testCluster description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - name: "testCluster", - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterItems: []moduleLib.Cluster{ - { - Metadata: moduleLib.Metadata{ - Name: "testCluster", - Description: "testCluster description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - ClusterContentItems: []moduleLib.ClusterContent{ - { - Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", - }, - }, - }, - }, - { - label: "Get Non-Existing Cluster", - accept: "application/json", - expectedCode: http.StatusInternalServerError, - name: "nonexistingcluster", - clusterClient: &mockClusterManager{ - ClusterItems: []moduleLib.Cluster{}, - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) - if len(testCase.accept) > 0 { - request.Header.Set("Accept", testCase.accept) - } - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := moduleLib.Cluster{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterGetContentHandler(t *testing.T) { - - testCases := []struct { - label string - expected string - name, version string - accept string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster Content with Accept: application/octet-stream", - accept: "application/octet-stream", - expectedCode: http.StatusOK, - expected: `test contents -of a file attached -to the creation -of clusterTest -`, - name: "testCluster", - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterItems: []moduleLib.Cluster{ - { - Metadata: moduleLib.Metadata{ - Name: "testCluster", - Description: "testCluster description", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - }, - }, - ClusterContentItems: []moduleLib.ClusterContent{ - { - Kubeconfig: "dGVzdCBjb250ZW50cwpvZiBhIGZpbGUgYXR0YWNoZWQKdG8gdGhlIGNyZWF0aW9uCm9mIGNsdXN0ZXJUZXN0Cg==", - }, - }, - }, - }, - { - label: "Get Non-Existing Cluster", - accept: "application/octet-stream", - expectedCode: http.StatusInternalServerError, - name: "nonexistingcluster", - clusterClient: &mockClusterManager{ - ClusterItems: []moduleLib.Cluster{}, - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) - if len(testCase.accept) > 0 { - request.Header.Set("Accept", testCase.accept) - } - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - body := new(bytes.Buffer) - body.ReadFrom(resp.Body) - got := body.String() - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterDeleteHandler(t *testing.T) { - - testCases := []struct { - label string - name string - version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Delete Cluster", - expectedCode: http.StatusNoContent, - name: "testCluster", - clusterClient: &mockClusterManager{}, - }, - { - label: "Delete Non-Existing Cluster", - expectedCode: http.StatusInternalServerError, - name: "testCluster", - clusterClient: &mockClusterManager{ - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("DELETE", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - }) - } -} - -func TestClusterLabelCreateHandler(t *testing.T) { - testCases := []struct { - label string - reader io.Reader - expected moduleLib.ClusterLabel - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Missing Cluster Label Body Failure", - expectedCode: http.StatusBadRequest, - clusterClient: &mockClusterManager{}, - }, - { - label: "Create Cluster Label", - expectedCode: http.StatusCreated, - reader: bytes.NewBuffer([]byte(`{ - "label-name": "test-label" - }`)), - expected: moduleLib.ClusterLabel{ - LabelName: "test-label", - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterLabelItems: []moduleLib.ClusterLabel{ - { - LabelName: "test-label", - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/labels", testCase.reader) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusCreated - if resp.StatusCode == http.StatusCreated { - got := moduleLib.ClusterLabel{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("createHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterLabelsGetHandler(t *testing.T) { - - testCases := []struct { - label string - expected []moduleLib.ClusterLabel - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster Labels", - expectedCode: http.StatusOK, - expected: []moduleLib.ClusterLabel{ - { - LabelName: "test-label1", - }, - { - LabelName: "test-label-two", - }, - { - LabelName: "test-label-3", - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterLabelItems: []moduleLib.ClusterLabel{ - { - LabelName: "test-label1", - }, - { - LabelName: "test-label-two", - }, - { - LabelName: "test-label-3", - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/labels", nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := []moduleLib.ClusterLabel{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterLabelGetHandler(t *testing.T) { - - testCases := []struct { - label string - expected moduleLib.ClusterLabel - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster Label", - expectedCode: http.StatusOK, - expected: moduleLib.ClusterLabel{ - LabelName: "testlabel", - }, - name: "testlabel", - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterLabelItems: []moduleLib.ClusterLabel{ - { - LabelName: "testlabel", - }, - }, - }, - }, - { - label: "Get Non-Existing Cluster Label", - expectedCode: http.StatusInternalServerError, - name: "nonexistingclusterlabel", - clusterClient: &mockClusterManager{ - ClusterLabelItems: []moduleLib.ClusterLabel{}, - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/labels/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := moduleLib.ClusterLabel{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterLabelDeleteHandler(t *testing.T) { - - testCases := []struct { - label string - name string - version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Delete Cluster Label", - expectedCode: http.StatusNoContent, - name: "testClusterLabel", - clusterClient: &mockClusterManager{}, - }, - { - label: "Delete Non-Existing Cluster Label", - expectedCode: http.StatusInternalServerError, - name: "testClusterLabel", - clusterClient: &mockClusterManager{ - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/labels/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - }) - } -} - -func TestClusterKvPairsCreateHandler(t *testing.T) { - testCases := []struct { - label string - reader io.Reader - expected moduleLib.ClusterKvPairs - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Missing Cluster KvPairs Body Failure", - expectedCode: http.StatusBadRequest, - clusterClient: &mockClusterManager{}, - }, - { - label: "Create Cluster KvPairs", - expectedCode: http.StatusCreated, - reader: bytes.NewBuffer([]byte(`{ - "metadata": { - "name": "ClusterKvPair1", - "description": "test cluster kv pairs", - "userData1": "some user data 1", - "userData2": "some user data 2" - }, - "spec": { - "kv": [ - { - "key1": "value1" - }, - { - "key2": "value2" - } - ] - } - }`)), - expected: moduleLib.ClusterKvPairs{ - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair1", - Description: "test cluster kv pairs", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "key1": "value1", - }, - { - "key2": "value2", - }, - }, - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair1", - Description: "test cluster kv pairs", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "key1": "value1", - }, - { - "key2": "value2", - }, - }, - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", testCase.reader) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusCreated - if resp.StatusCode == http.StatusCreated { - got := moduleLib.ClusterKvPairs{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("createHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterKvPairsGetAllHandler(t *testing.T) { - - testCases := []struct { - label string - expected []moduleLib.ClusterKvPairs - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster KvPairs", - expectedCode: http.StatusOK, - expected: []moduleLib.ClusterKvPairs{ - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair1", - Description: "test cluster kv pairs", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "key1": "value1", - }, - { - "key2": "value2", - }, - }, - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair2", - Description: "test cluster kv pairs", - UserData1: "some user data A", - UserData2: "some user data B", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "keyA": "valueA", - }, - { - "keyB": "valueB", - }, - }, - }, - }, - }, - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair1", - Description: "test cluster kv pairs", - UserData1: "some user data 1", - UserData2: "some user data 2", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "key1": "value1", - }, - { - "key2": "value2", - }, - }, - }, - }, - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair2", - Description: "test cluster kv pairs", - UserData1: "some user data A", - UserData2: "some user data B", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "keyA": "valueA", - }, - { - "keyB": "valueB", - }, - }, - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := []moduleLib.ClusterKvPairs{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterKvPairsGetHandler(t *testing.T) { - - testCases := []struct { - label string - expected moduleLib.ClusterKvPairs - name, version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Get Cluster KV Pairs", - expectedCode: http.StatusOK, - expected: moduleLib.ClusterKvPairs{ - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair2", - Description: "test cluster kv pairs", - UserData1: "some user data A", - UserData2: "some user data B", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "keyA": "valueA", - }, - { - "keyB": "valueB", - }, - }, - }, - }, - name: "ClusterKvPair2", - clusterClient: &mockClusterManager{ - //Items that will be returned by the mocked Client - ClusterKvPairsItems: []moduleLib.ClusterKvPairs{ - { - Metadata: moduleLib.Metadata{ - Name: "ClusterKvPair2", - Description: "test cluster kv pairs", - UserData1: "some user data A", - UserData2: "some user data B", - }, - Spec: moduleLib.ClusterKvSpec{ - Kv: []map[string]interface{}{ - { - "keyA": "valueA", - }, - { - "keyB": "valueB", - }, - }, - }, - }, - }, - }, - }, - { - label: "Get Non-Existing Cluster KV Pairs", - expectedCode: http.StatusInternalServerError, - name: "nonexistingclusterkvpairs", - clusterClient: &mockClusterManager{ - ClusterKvPairsItems: []moduleLib.ClusterKvPairs{}, - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/kv-pairs/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := moduleLib.ClusterKvPairs{} - json.NewDecoder(resp.Body).Decode(&got) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestClusterKvPairsDeleteHandler(t *testing.T) { - - testCases := []struct { - label string - name string - version string - expectedCode int - clusterClient *mockClusterManager - }{ - { - label: "Delete Cluster KV Pairs", - expectedCode: http.StatusNoContent, - name: "testClusterKvPairs", - clusterClient: &mockClusterManager{}, - }, - { - label: "Delete Non-Existing Cluster KV Pairs", - expectedCode: http.StatusInternalServerError, - name: "testClusterKvPairs", - clusterClient: &mockClusterManager{ - Err: pkgerrors.New("Internal Error"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil, nil)) - - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - }) - } -} diff --git a/src/orchestrator/api/composite_profilehandler_test.go b/src/orchestrator/api/composite_profilehandler_test.go index 7c84f12a..360653c7 100644 --- a/src/orchestrator/api/composite_profilehandler_test.go +++ b/src/orchestrator/api/composite_profilehandler_test.go @@ -128,7 +128,7 @@ func Test_compositeProfileHandler_createHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("POST", "/v2/projects/{project-name}/composite-apps/{composite-app-name}/{version}/composite-profiles", testCase.reader) - resp := executeRequest(request, NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil, testCase.cProfClient, nil)) + resp := executeRequest(request, NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, testCase.cProfClient, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { diff --git a/src/orchestrator/api/controllerhandler_test.go b/src/orchestrator/api/controllerhandler_test.go index 3c543cb8..1844fb32 100644 --- a/src/orchestrator/api/controllerhandler_test.go +++ b/src/orchestrator/api/controllerhandler_test.go @@ -110,7 +110,7 @@ func TestControllerCreateHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("POST", "/v2/controllers", testCase.reader) - resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { @@ -173,7 +173,7 @@ func TestControllerGetHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("GET", "/v2/controllers/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { @@ -222,7 +222,7 @@ func TestControllerDeleteHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("DELETE", "/v2/controllers/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { diff --git a/src/orchestrator/api/projecthandler_test.go b/src/orchestrator/api/projecthandler_test.go index 5e820aa2..af40f961 100644 --- a/src/orchestrator/api/projecthandler_test.go +++ b/src/orchestrator/api/projecthandler_test.go @@ -119,7 +119,7 @@ func TestProjectCreateHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("POST", "/v2/projects", testCase.reader) - resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { @@ -188,7 +188,7 @@ func TestProjectGetHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("GET", "/v2/projects/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { @@ -237,7 +237,7 @@ func TestProjectDeleteHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { request := httptest.NewRequest("DELETE", "/v2/projects/"+testCase.name, nil) - resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) + resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil, nil)) //Check returned code if resp.StatusCode != testCase.expectedCode { diff --git a/src/orchestrator/cmd/main.go b/src/orchestrator/cmd/main.go index 001903a7..f95c057e 100644 --- a/src/orchestrator/cmd/main.go +++ b/src/orchestrator/cmd/main.go @@ -47,7 +47,7 @@ func main() { log.Fatalln("Exiting...") } - httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter) log.Println("Starting Kubernetes Multicloud API") diff --git a/src/orchestrator/pkg/module/cluster.go b/src/orchestrator/pkg/module/cluster.go deleted file mode 100644 index c9ddad6e..00000000 --- a/src/orchestrator/pkg/module/cluster.go +++ /dev/null @@ -1,540 +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" -) - -// ClusterProvider contains the parameters needed for ClusterProviders -// It implements the interface for managing the ClusterProviders -type Metadata struct { - Name string `json:"name"` - Description string `json:"description"` - UserData1 string `json:"userData1"` - UserData2 string `json:"userData2"` -} - -type ClusterProvider struct { - Metadata Metadata `json:"metadata"` -} - -type Cluster struct { - Metadata Metadata `json:"metadata"` -} - -type ClusterContent struct { - Kubeconfig string `json:"kubeconfig"` -} - -type ClusterLabel struct { - LabelName string `json:"label-name"` -} - -type ClusterKvPairs struct { - Metadata Metadata `json:"metadata"` - Spec ClusterKvSpec `json:"spec"` -} - -type ClusterKvSpec struct { - Kv []map[string]interface{} `json:"kv"` -} - -// ClusterProviderKey is the key structure that is used in the database -type ClusterProviderKey struct { - ClusterProviderName string `json:"provider"` -} - -// ClusterKey is the key structure that is used in the database -type ClusterKey struct { - ClusterProviderName string `json:"provider"` - ClusterName string `json:"cluster"` -} - -// ClusterLabelKey is the key structure that is used in the database -type ClusterLabelKey struct { - ClusterProviderName string `json:"provider"` - ClusterName string `json:"cluster"` - ClusterLabelName string `json:"label"` -} - -// ClusterKvPairsKey is the key structure that is used in the database -type ClusterKvPairsKey struct { - ClusterProviderName string `json:"provider"` - ClusterName string `json:"cluster"` - ClusterKvPairsName string `json:"kvname"` -} - -// Manager is an interface exposes the Cluster functionality -type ClusterManager interface { - CreateClusterProvider(pr ClusterProvider) (ClusterProvider, error) - GetClusterProvider(name string) (ClusterProvider, error) - GetClusterProviders() ([]ClusterProvider, error) - DeleteClusterProvider(name string) error - CreateCluster(provider string, pr Cluster, qr ClusterContent) (Cluster, error) - GetCluster(provider, name string) (Cluster, error) - GetClusterContent(provider, name string) (ClusterContent, error) - GetClusters(provider string) ([]Cluster, error) - DeleteCluster(provider, name string) error - CreateClusterLabel(provider, cluster string, pr ClusterLabel) (ClusterLabel, error) - GetClusterLabel(provider, cluster, label string) (ClusterLabel, error) - GetClusterLabels(provider, cluster string) ([]ClusterLabel, error) - DeleteClusterLabel(provider, cluster, label string) error - CreateClusterKvPairs(provider, cluster string, pr ClusterKvPairs) (ClusterKvPairs, error) - GetClusterKvPairs(provider, cluster, kvpair string) (ClusterKvPairs, error) - GetAllClusterKvPairs(provider, cluster string) ([]ClusterKvPairs, error) - DeleteClusterKvPairs(provider, cluster, kvpair string) error -} - -// ClusterClient implements the Manager -// It will also be used to maintain some localized state -type ClusterClient struct { - storeName string - tagMeta string - tagContent string -} - -// NewClusterClient returns an instance of the ClusterClient -// which implements the Manager -func NewClusterClient() *ClusterClient { - return &ClusterClient{ - storeName: "cluster", - tagMeta: "clustermetadata", - tagContent: "clustercontent", - } -} - -// CreateClusterProvider - create a new Cluster Provider -func (v *ClusterClient) CreateClusterProvider(p ClusterProvider) (ClusterProvider, error) { - - //Construct key and tag to select the entry - key := ClusterProviderKey{ - ClusterProviderName: p.Metadata.Name, - } - - //Check if this ClusterProvider already exists - _, err := v.GetClusterProvider(p.Metadata.Name) - if err == nil { - return ClusterProvider{}, pkgerrors.New("ClusterProvider already exists") - } - - err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) - if err != nil { - return ClusterProvider{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return p, nil -} - -// GetClusterProvider returns the ClusterProvider for corresponding name -func (v *ClusterClient) GetClusterProvider(name string) (ClusterProvider, error) { - - //Construct key and tag to select the entry - key := ClusterProviderKey{ - ClusterProviderName: name, - } - - value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return ClusterProvider{}, pkgerrors.Wrap(err, "Get ClusterProvider") - } - - //value is a byte array - if value != nil { - cp := ClusterProvider{} - err = db.DBconn.Unmarshal(value[0], &cp) - if err != nil { - return ClusterProvider{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - return cp, nil - } - - return ClusterProvider{}, pkgerrors.New("Error getting ClusterProvider") -} - -// GetClusterProviderList returns all of the ClusterProvider for corresponding name -func (v *ClusterClient) GetClusterProviders() ([]ClusterProvider, error) { - - //Construct key and tag to select the entry - key := ClusterProviderKey{ - ClusterProviderName: "", - } - - var resp []ClusterProvider - values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return []ClusterProvider{}, pkgerrors.Wrap(err, "Get ClusterProviders") - } - - for _, value := range values { - cp := ClusterProvider{} - err = db.DBconn.Unmarshal(value, &cp) - if err != nil { - return []ClusterProvider{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - resp = append(resp, cp) - } - - return resp, nil -} - -// DeleteClusterProvider the ClusterProvider from database -func (v *ClusterClient) DeleteClusterProvider(name string) error { - - //Construct key and tag to select the entry - key := ClusterProviderKey{ - ClusterProviderName: name, - } - - err := db.DBconn.Remove(v.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete ClusterProvider Entry;") - } - - return nil -} - -// CreateCluster - create a new Cluster for a cluster-provider -func (v *ClusterClient) CreateCluster(provider string, p Cluster, q ClusterContent) (Cluster, error) { - - //Construct key and tag to select the entry - key := ClusterKey{ - ClusterProviderName: provider, - ClusterName: p.Metadata.Name, - } - - //Verify ClusterProvider already exists - _, err := v.GetClusterProvider(provider) - if err != nil { - return Cluster{}, pkgerrors.New("ClusterProvider does not exist") - } - - //Check if this Cluster already exists - _, err = v.GetCluster(provider, p.Metadata.Name) - if err == nil { - return Cluster{}, pkgerrors.New("Cluster already exists") - } - - err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) - if err != nil { - return Cluster{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - err = db.DBconn.Insert(v.storeName, key, nil, v.tagContent, q) - if err != nil { - return Cluster{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return p, nil -} - -// GetCluster returns the Cluster for corresponding provider and name -func (v *ClusterClient) GetCluster(provider, name string) (Cluster, error) { - //Construct key and tag to select the entry - key := ClusterKey{ - ClusterProviderName: provider, - ClusterName: name, - } - - value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return Cluster{}, pkgerrors.Wrap(err, "Get Cluster") - } - - //value is a byte array - if value != nil { - cl := Cluster{} - err = db.DBconn.Unmarshal(value[0], &cl) - if err != nil { - return Cluster{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - return cl, nil - } - - return Cluster{}, pkgerrors.New("Error getting Cluster") -} - -// GetClusterContent returns the ClusterContent for corresponding provider and name -func (v *ClusterClient) GetClusterContent(provider, name string) (ClusterContent, error) { - //Construct key and tag to select the entry - key := ClusterKey{ - ClusterProviderName: provider, - ClusterName: name, - } - - value, err := db.DBconn.Find(v.storeName, key, v.tagContent) - if err != nil { - return ClusterContent{}, pkgerrors.Wrap(err, "Get Cluster Content") - } - - //value is a byte array - if value != nil { - cc := ClusterContent{} - err = db.DBconn.Unmarshal(value[0], &cc) - if err != nil { - return ClusterContent{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - return cc, nil - } - - return ClusterContent{}, pkgerrors.New("Error getting Cluster Content") -} - -// GetClusters returns all the Clusters for corresponding provider -func (v *ClusterClient) GetClusters(provider string) ([]Cluster, error) { - //Construct key and tag to select the entry - key := ClusterKey{ - ClusterProviderName: provider, - ClusterName: "", - } - - values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return []Cluster{}, pkgerrors.Wrap(err, "Get Clusters") - } - - var resp []Cluster - - for _, value := range values { - cp := Cluster{} - err = db.DBconn.Unmarshal(value, &cp) - if err != nil { - return []Cluster{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - resp = append(resp, cp) - } - - return resp, nil -} - -// DeleteCluster the Cluster from database -func (v *ClusterClient) DeleteCluster(provider, name string) error { - //Construct key and tag to select the entry - key := ClusterKey{ - ClusterProviderName: provider, - ClusterName: name, - } - - err := db.DBconn.Remove(v.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete Cluster Entry;") - } - - return nil -} - -// CreateClusterLabel - create a new Cluster Label mongo document for a cluster-provider/cluster -func (v *ClusterClient) CreateClusterLabel(provider string, cluster string, p ClusterLabel) (ClusterLabel, error) { - //Construct key and tag to select the entry - key := ClusterLabelKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterLabelName: p.LabelName, - } - - //Verify Cluster already exists - _, err := v.GetCluster(provider, cluster) - if err != nil { - return ClusterLabel{}, pkgerrors.New("Cluster does not exist") - } - - //Check if this ClusterLabel already exists - _, err = v.GetClusterLabel(provider, cluster, p.LabelName) - if err == nil { - return ClusterLabel{}, pkgerrors.New("Cluster Label already exists") - } - - err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) - if err != nil { - return ClusterLabel{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return p, nil -} - -// GetClusterLabel returns the Cluster for corresponding provider, cluster and label -func (v *ClusterClient) GetClusterLabel(provider, cluster, label string) (ClusterLabel, error) { - //Construct key and tag to select the entry - key := ClusterLabelKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterLabelName: label, - } - - value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return ClusterLabel{}, pkgerrors.Wrap(err, "Get Cluster") - } - - //value is a byte array - if value != nil { - cl := ClusterLabel{} - err = db.DBconn.Unmarshal(value[0], &cl) - if err != nil { - return ClusterLabel{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - return cl, nil - } - - return ClusterLabel{}, pkgerrors.New("Error getting Cluster") -} - -// GetClusterLabels returns the Cluster Labels for corresponding provider and cluster -func (v *ClusterClient) GetClusterLabels(provider, cluster string) ([]ClusterLabel, error) { - //Construct key and tag to select the entry - key := ClusterLabelKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterLabelName: "", - } - - values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return []ClusterLabel{}, pkgerrors.Wrap(err, "Get Cluster Labels") - } - - var resp []ClusterLabel - - for _, value := range values { - cp := ClusterLabel{} - err = db.DBconn.Unmarshal(value, &cp) - if err != nil { - return []ClusterLabel{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - resp = append(resp, cp) - } - - return resp, nil -} - -// Delete the Cluster Label from database -func (v *ClusterClient) DeleteClusterLabel(provider, cluster, label string) error { - //Construct key and tag to select the entry - key := ClusterLabelKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterLabelName: label, - } - - err := db.DBconn.Remove(v.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete ClusterLabel Entry;") - } - - return nil -} - -// CreateClusterKvPairs - Create a New Cluster KV pairs document -func (v *ClusterClient) CreateClusterKvPairs(provider string, cluster string, p ClusterKvPairs) (ClusterKvPairs, error) { - key := ClusterKvPairsKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterKvPairsName: p.Metadata.Name, - } - - //Verify Cluster already exists - _, err := v.GetCluster(provider, cluster) - if err != nil { - return ClusterKvPairs{}, pkgerrors.New("Cluster does not exist") - } - - //Check if this ClusterKvPairs already exists - _, err = v.GetClusterKvPairs(provider, cluster, p.Metadata.Name) - if err == nil { - return ClusterKvPairs{}, pkgerrors.New("Cluster KV Pair already exists") - } - - err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, p) - if err != nil { - return ClusterKvPairs{}, pkgerrors.Wrap(err, "Creating DB Entry") - } - - return p, nil -} - -// GetClusterKvPairs returns the Cluster KeyValue pair for corresponding provider, cluster and KV pair name -func (v *ClusterClient) GetClusterKvPairs(provider, cluster, kvpair string) (ClusterKvPairs, error) { - //Construct key and tag to select entry - key := ClusterKvPairsKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterKvPairsName: kvpair, - } - - value, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return ClusterKvPairs{}, pkgerrors.Wrap(err, "Get Cluster") - } - - //value is a byte array - if value != nil { - ckvp := ClusterKvPairs{} - err = db.DBconn.Unmarshal(value[0], &ckvp) - if err != nil { - return ClusterKvPairs{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - return ckvp, nil - } - - return ClusterKvPairs{}, pkgerrors.New("Error getting Cluster") -} - -// GetAllClusterKvPairs returns the Cluster Kv Pairs for corresponding provider and cluster -func (v *ClusterClient) GetAllClusterKvPairs(provider, cluster string) ([]ClusterKvPairs, error) { - //Construct key and tag to select the entry - key := ClusterKvPairsKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterKvPairsName: "", - } - - values, err := db.DBconn.Find(v.storeName, key, v.tagMeta) - if err != nil { - return []ClusterKvPairs{}, pkgerrors.Wrap(err, "Get Cluster KV Pairs") - } - - var resp []ClusterKvPairs - - for _, value := range values { - cp := ClusterKvPairs{} - err = db.DBconn.Unmarshal(value, &cp) - if err != nil { - return []ClusterKvPairs{}, pkgerrors.Wrap(err, "Unmarshaling Value") - } - resp = append(resp, cp) - } - - return resp, nil -} - -// DeleteClusterKvPairs the ClusterKvPairs from database -func (v *ClusterClient) DeleteClusterKvPairs(provider, cluster, kvpair string) error { - //Construct key and tag to select entry - key := ClusterKvPairsKey{ - ClusterProviderName: provider, - ClusterName: cluster, - ClusterKvPairsName: kvpair, - } - - err := db.DBconn.Remove(v.storeName, key) - if err != nil { - return pkgerrors.Wrap(err, "Delete ClusterKvPairs Entry;") - } - - return nil -} diff --git a/src/orchestrator/pkg/module/module.go b/src/orchestrator/pkg/module/module.go index 77a2f5bf..c697bbff 100644 --- a/src/orchestrator/pkg/module/module.go +++ b/src/orchestrator/pkg/module/module.go @@ -22,7 +22,6 @@ type Client struct { CompositeApp *CompositeAppClient App *AppClient Controller *ControllerClient - Cluster *ClusterClient GenericPlacementIntent *GenericPlacementIntentClient AppIntent *AppIntentClient DeploymentIntentGroup *DeploymentIntentGroupClient @@ -39,7 +38,6 @@ func NewClient() *Client { c.CompositeApp = NewCompositeAppClient() c.App = NewAppClient() c.Controller = NewControllerClient() - c.Cluster = NewClusterClient() c.GenericPlacementIntent = NewGenericPlacementIntentClient() c.AppIntent = NewAppIntentClient() c.DeploymentIntentGroup = NewDeploymentIntentGroupClient() -- cgit 1.2.3-korg