Refactor instance code 96/83996/2
authorKiran Kamineni <kiran.k.kamineni@intel.com>
Thu, 28 Mar 2019 19:53:13 +0000 (12:53 -0700)
committerKiran Kamineni <kiran.k.kamineni@intel.com>
Wed, 3 Apr 2019 22:31:31 +0000 (15:31 -0700)
Issue-ID: MULTICLOUD-350
Change-Id: I2574d94e4ebada1e138913b2a03549dd90906d7b
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
16 files changed:
src/k8splugin/api/api.go
src/k8splugin/api/handler.go [deleted file]
src/k8splugin/api/handler_test.go [deleted file]
src/k8splugin/api/instancehandler.go [new file with mode: 0644]
src/k8splugin/api/instancehandler_test.go [new file with mode: 0644]
src/k8splugin/cmd/main.go
src/k8splugin/internal/app/client.go
src/k8splugin/internal/app/client_test.go
src/k8splugin/internal/app/instance.go [new file with mode: 0644]
src/k8splugin/internal/app/instance_test.go [moved from src/k8splugin/internal/app/vnfhelper_test.go with 65% similarity]
src/k8splugin/internal/app/vnfhelper.go [deleted file]
src/k8splugin/mock_files/mock_plugins/mockplugin.go
src/k8splugin/plugins/deployment/plugin.go
src/k8splugin/plugins/deployment/plugin_test.go
src/k8splugin/plugins/service/plugin.go
src/k8splugin/plugins/service/plugin_test.go

index 2862a99..54147d2 100644 (file)
@@ -14,21 +14,30 @@ limitations under the License.
 package api
 
 import (
+       "k8splugin/internal/app"
        "k8splugin/internal/rb"
 
        "github.com/gorilla/mux"
 )
 
-// NewRouter creates a router instance that serves the VNFInstance web methods
-func NewRouter(kubeconfig string, defClient rb.DefinitionManager,
-       profileClient rb.ProfileManager) *mux.Router {
+// NewRouter creates a router that registers the various urls that are supported
+func NewRouter(defClient rb.DefinitionManager,
+       profileClient rb.ProfileManager,
+       instClient app.InstanceManager) *mux.Router {
+
        router := mux.NewRouter()
 
-       vnfInstanceHandler := router.PathPrefix("/v1/vnf_instances").Subrouter()
-       vnfInstanceHandler.HandleFunc("/", CreateHandler).Methods("POST").Name("VNFCreation")
-       vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}", ListHandler).Methods("GET")
-       vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", DeleteHandler).Methods("DELETE")
-       vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", GetHandler).Methods("GET")
+       // Setup Instance handler routes
+       if instClient == nil {
+               instClient = app.NewInstanceClient()
+       }
+       instHandler := instanceHandler{client: instClient}
+       instRouter := router.PathPrefix("/v1").Subrouter()
+       instRouter.HandleFunc("/instance", instHandler.createHandler).Methods("POST")
+       instRouter.HandleFunc("/instance/{instID}", instHandler.getHandler).Methods("GET")
+       instRouter.HandleFunc("/instance/{instID}", instHandler.deleteHandler).Methods("DELETE")
+       // (TODO): Fix update method
+       // instRouter.HandleFunc("/{vnfInstanceId}", UpdateHandler).Methods("PUT")
 
        //Setup resource bundle definition routes
        if defClient == nil {
@@ -52,8 +61,5 @@ func NewRouter(kubeconfig string, defClient rb.DefinitionManager,
        resRouter.HandleFunc("/definition/{rbname}/{rbversion}/profile/{prname}", profileHandler.getHandler).Methods("GET")
        resRouter.HandleFunc("/definition/{rbname}/{rbversion}/profile/{prname}", profileHandler.deleteHandler).Methods("DELETE")
 
-       // (TODO): Fix update method
-       // vnfInstanceHandler.HandleFunc("/{vnfInstanceId}", UpdateHandler).Methods("PUT")
-
        return router
 }
diff --git a/src/k8splugin/api/handler.go b/src/k8splugin/api/handler.go
deleted file mode 100644 (file)
index 31ffad9..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
-Copyright 2018 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 api
-
-import (
-       "encoding/json"
-       "errors"
-       "io"
-       "log"
-       "net/http"
-       "os"
-       "strings"
-
-       "github.com/gorilla/mux"
-       pkgerrors "github.com/pkg/errors"
-       "k8s.io/client-go/kubernetes"
-
-       helper "k8splugin/internal/app"
-       "k8splugin/internal/db"
-       "k8splugin/internal/rb"
-)
-
-//TODO: Separate the http handler code and backend code out
-var storeName = "rbinst"
-var tagData = "data"
-
-type instanceKey struct {
-       Key string
-}
-
-func (dk instanceKey) String() string {
-       return dk.Key
-}
-
-// GetVNFClient retrieves the client used to communicate with a Kubernetes Cluster
-var GetVNFClient = func(kubeConfigPath string) (kubernetes.Clientset, error) {
-       client, err := helper.GetKubeClient(kubeConfigPath)
-       if err != nil {
-               return client, err
-       }
-       return client, nil
-}
-
-func validateBody(body interface{}) error {
-       switch b := body.(type) {
-       case CreateVnfRequest:
-               if b.CloudRegionID == "" {
-                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing CloudRegionID in POST request"), "CreateVnfRequest bad request")
-                       return werr
-               }
-               if b.CsarID == "" {
-                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing CsarID in POST request"), "CreateVnfRequest bad request")
-                       return werr
-               }
-               if b.RBName == "" || b.RBVersion == "" {
-                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing resource bundle parameters in POST request"), "CreateVnfRequest bad request")
-                       return werr
-               }
-               if b.ProfileName == "" {
-                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing profile name in POST request"), "CreateVnfRequest bad request")
-                       return werr
-               }
-               if strings.Contains(b.CloudRegionID, "|") {
-                       werr := pkgerrors.Wrap(errors.New("Character \"|\" not allowed in CSAR ID"), "CreateVnfRequest bad request")
-                       return werr
-               }
-       case UpdateVnfRequest:
-               if b.CloudRegionID == "" || b.CsarID == "" {
-                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing Data in PUT request"), "UpdateVnfRequest bad request")
-                       return werr
-               }
-       }
-       return nil
-}
-
-// CreateHandler is the POST method creates a new VNF instance resource.
-func CreateHandler(w http.ResponseWriter, r *http.Request) {
-       var resource CreateVnfRequest
-
-       err := json.NewDecoder(r.Body).Decode(&resource)
-       switch {
-       case err == io.EOF:
-               http.Error(w, "Body empty", http.StatusBadRequest)
-               return
-       case err != nil:
-               http.Error(w, err.Error(), http.StatusUnprocessableEntity)
-               return
-       }
-
-       err = validateBody(resource)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusUnprocessableEntity)
-               return
-       }
-
-       // (TODO): Read kubeconfig for specific Cloud Region from local file system
-       // if present or download it from AAI
-       // err := DownloadKubeConfigFromAAI(resource.CloudRegionID, os.Getenv("KUBE_CONFIG_DIR")
-       kubeclient, err := GetVNFClient(os.Getenv("KUBE_CONFIG_DIR") + "/" + resource.CloudRegionID)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       /*
-               uuid,
-               {
-                       "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
-                       "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
-               },
-               nil
-       */
-       profile, err := rb.NewProfileClient().Get(resource.RBName, resource.RBVersion, resource.ProfileName)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-       externalVNFID, resourceNameMap, err := helper.CreateVNF(resource.CsarID, resource.CloudRegionID,
-               profile, &kubeclient)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Read Kubernetes Data information error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       namespace := profile.Namespace
-       // cloud1-default-uuid
-       internalVNFID := resource.CloudRegionID + "-" + namespace + "-" + externalVNFID
-
-       // Persist in AAI database.
-       log.Printf("Cloud Region ID: %s, Namespace: %s, VNF ID: %s ", resource.CloudRegionID, namespace, externalVNFID)
-
-       // TODO: Uncomment when annotations are done
-       // krd.AddNetworkAnnotationsToPod(kubeData, resource.Networks)
-
-       // key: cloud1-default-uuid
-       // value: "{"deployment":<>,"service":<>}"
-       err = db.DBconn.Create(storeName, instanceKey{Key: internalVNFID}, tagData, resourceNameMap)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Create VNF deployment DB error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       resp := CreateVnfResponse{
-               VNFID:         externalVNFID,
-               CloudRegionID: resource.CloudRegionID,
-               Namespace:     namespace,
-               VNFComponents: resourceNameMap,
-       }
-
-       w.Header().Set("Content-Type", "application/json")
-       w.WriteHeader(http.StatusCreated)
-       json.NewEncoder(w).Encode(resp)
-}
-
-// ListHandler the existing VNF instances created in a given Kubernetes cluster
-func ListHandler(w http.ResponseWriter, r *http.Request) {
-       vars := mux.Vars(r)
-
-       cloudRegionID := vars["cloudRegionID"]
-       namespace := vars["namespace"]
-       prefix := cloudRegionID + "-" + namespace
-
-       res, err := db.DBconn.ReadAll(storeName, tagData)
-       if err != nil {
-               http.Error(w, pkgerrors.Wrap(err, "Get VNF list error").Error(),
-                       http.StatusInternalServerError)
-               return
-       }
-
-       // TODO: There is an edge case where if namespace is passed but is missing some characters
-       // trailing, it will print the result with those excluding characters. This is because of
-       // the way I am trimming the Prefix. This fix is needed.
-
-       var editedList []string
-
-       for key, value := range res {
-               if len(value) > 0 {
-                       editedList = append(editedList, strings.TrimPrefix(key, prefix)[1:])
-               }
-       }
-
-       if len(editedList) == 0 {
-               editedList = append(editedList, "")
-       }
-
-       resp := ListVnfsResponse{
-               VNFs: editedList,
-       }
-
-       w.Header().Set("Content-Type", "application/json")
-       w.WriteHeader(http.StatusOK)
-       json.NewEncoder(w).Encode(resp)
-}
-
-// DeleteHandler method terminates an individual VNF instance.
-func DeleteHandler(w http.ResponseWriter, r *http.Request) {
-       vars := mux.Vars(r)
-
-       cloudRegionID := vars["cloudRegionID"] // cloud1
-       namespace := vars["namespace"]         // default
-       externalVNFID := vars["externalVNFID"] // uuid
-
-       // cloud1-default-uuid
-       internalVNFID := cloudRegionID + "-" + namespace + "-" + externalVNFID
-
-       // key: cloud1-default-uuid
-       // value: "{"deployment":<>,"service":<>}"
-       res, err := db.DBconn.Read(storeName, instanceKey{Key: internalVNFID}, tagData)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       /*
-               {
-                       "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
-                       "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
-               },
-       */
-       data := make(map[string][]string)
-       err = db.DBconn.Unmarshal(res, &data)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Unmarshal VNF error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       // (TODO): Read kubeconfig for specific Cloud Region from local file system
-       // if present or download it from AAI
-       // err := DownloadKubeConfigFromAAI(resource.CloudRegionID, os.Getenv("KUBE_CONFIG_DIR")
-       kubeclient, err := GetVNFClient(os.Getenv("KUBE_CONFIG_DIR") + "/" + cloudRegionID)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-       err = helper.DestroyVNF(data, namespace, &kubeclient)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Delete VNF error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       err = db.DBconn.Delete(storeName, instanceKey{Key: internalVNFID}, tagData)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Delete VNF db record error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       w.Header().Set("Content-Type", "application/json")
-       w.WriteHeader(http.StatusAccepted)
-}
-
-// // UpdateHandler method to update a VNF instance.
-// func UpdateHandler(w http.ResponseWriter, r *http.Request) {
-//     vars := mux.Vars(r)
-//     id := vars["vnfInstanceId"]
-
-//     var resource UpdateVnfRequest
-
-//     if r.Body == nil {
-//             http.Error(w, "Body empty", http.StatusBadRequest)
-//             return
-//     }
-
-//     err := json.NewDecoder(r.Body).Decode(&resource)
-//     if err != nil {
-//             http.Error(w, err.Error(), http.StatusUnprocessableEntity)
-//             return
-//     }
-
-//     err = validateBody(resource)
-//     if err != nil {
-//             http.Error(w, err.Error(), http.StatusUnprocessableEntity)
-//             return
-//     }
-
-//     kubeData, err := utils.ReadCSARFromFileSystem(resource.CsarID)
-
-//     if kubeData.Deployment == nil {
-//             werr := pkgerrors.Wrap(err, "Update VNF deployment error")
-//             http.Error(w, werr.Error(), http.StatusInternalServerError)
-//             return
-//     }
-//     kubeData.Deployment.SetUID(types.UID(id))
-
-//     if err != nil {
-//             werr := pkgerrors.Wrap(err, "Update VNF deployment information error")
-//             http.Error(w, werr.Error(), http.StatusInternalServerError)
-//             return
-//     }
-
-//     // (TODO): Read kubeconfig for specific Cloud Region from local file system
-//     // if present or download it from AAI
-//     s, err := NewVNFInstanceService("../kubeconfig/config")
-//     if err != nil {
-//             http.Error(w, err.Error(), http.StatusInternalServerError)
-//             return
-//     }
-
-//     err = s.Client.UpdateDeployment(kubeData.Deployment, resource.Namespace)
-//     if err != nil {
-//             werr := pkgerrors.Wrap(err, "Update VNF error")
-
-//             http.Error(w, werr.Error(), http.StatusInternalServerError)
-//             return
-//     }
-
-//     resp := UpdateVnfResponse{
-//             DeploymentID: id,
-//     }
-
-//     w.Header().Set("Content-Type", "application/json")
-//     w.WriteHeader(http.StatusCreated)
-
-//     err = json.NewEncoder(w).Encode(resp)
-//     if err != nil {
-//             werr := pkgerrors.Wrap(err, "Parsing output of new VNF error")
-//             http.Error(w, werr.Error(), http.StatusInternalServerError)
-//     }
-// }
-
-// GetHandler retrieves information about a VNF instance by reading an individual VNF instance resource.
-func GetHandler(w http.ResponseWriter, r *http.Request) {
-       vars := mux.Vars(r)
-
-       cloudRegionID := vars["cloudRegionID"] // cloud1
-       namespace := vars["namespace"]         // default
-       externalVNFID := vars["externalVNFID"] // uuid
-
-       // cloud1-default-uuid
-       internalVNFID := cloudRegionID + "-" + namespace + "-" + externalVNFID
-
-       // key: cloud1-default-uuid
-       // value: "{"deployment":<>,"service":<>}"
-       res, err := db.DBconn.Read(storeName, instanceKey{Key: internalVNFID}, tagData)
-       if err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       /*
-               {
-                       "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
-                       "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
-               },
-       */
-       data := make(map[string][]string)
-       err = db.DBconn.Unmarshal(res, &data)
-       if err != nil {
-               werr := pkgerrors.Wrap(err, "Unmarshal VNF error")
-               http.Error(w, werr.Error(), http.StatusInternalServerError)
-               return
-       }
-
-       resp := GetVnfResponse{
-               VNFID:         externalVNFID,
-               CloudRegionID: cloudRegionID,
-               Namespace:     namespace,
-               VNFComponents: data,
-       }
-
-       w.Header().Set("Content-Type", "application/json")
-       w.WriteHeader(http.StatusOK)
-       json.NewEncoder(w).Encode(resp)
-}
diff --git a/src/k8splugin/api/handler_test.go b/src/k8splugin/api/handler_test.go
deleted file mode 100644 (file)
index cb377ea..0000000
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
-Copyright 2018 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 api
-
-import (
-       "bytes"
-       "encoding/json"
-       "io"
-       "net/http"
-       "net/http/httptest"
-       "reflect"
-       "testing"
-
-       pkgerrors "github.com/pkg/errors"
-       "k8s.io/client-go/kubernetes"
-
-       helper "k8splugin/internal/app"
-       "k8splugin/internal/db"
-       "k8splugin/internal/rb"
-)
-
-type mockCSAR struct {
-       externalVNFID       string
-       resourceYAMLNameMap map[string][]string
-       err                 error
-}
-
-func (c *mockCSAR) CreateVNF(id string, r string, profile rb.Profile,
-       kubeclient *kubernetes.Clientset) (string, map[string][]string, error) {
-       return c.externalVNFID, c.resourceYAMLNameMap, c.err
-}
-
-func (c *mockCSAR) DestroyVNF(data map[string][]string, namespace string,
-       kubeclient *kubernetes.Clientset) error {
-       return c.err
-}
-
-func executeRequest(req *http.Request) *http.Response {
-       router := NewRouter("", nil, nil)
-       recorder := httptest.NewRecorder()
-       router.ServeHTTP(recorder, req)
-
-       return recorder.Result()
-}
-
-func checkResponseCode(t *testing.T, expected, actual int) {
-       if expected != actual {
-               t.Errorf("Expected response code %d. Got %d\n", expected, actual)
-       }
-}
-
-func TestCreateHandler(t *testing.T) {
-       testCases := []struct {
-               label               string
-               input               io.Reader
-               expectedCode        int
-               mockGetVNFClientErr error
-               mockCreateVNF       *mockCSAR
-               mockStore           *db.MockDB
-       }{
-               {
-                       label:        "Missing body failure",
-                       expectedCode: http.StatusBadRequest,
-               },
-               {
-                       label:        "Invalid JSON request format",
-                       input:        bytes.NewBuffer([]byte("invalid")),
-                       expectedCode: http.StatusUnprocessableEntity,
-               },
-               {
-                       label: "Missing parameter failure",
-                       input: bytes.NewBuffer([]byte(`{
-                               "csar_id": "testID",
-                               "rb-name": "test-rbdef",
-                               "rb-version": "v1",
-                               "oof_parameters": [{
-                                       "key_values": {
-                                               "key1": "value1",
-                                               "key2": "value2"
-                                       }
-                               }],
-                               "vnf_instance_name": "test",
-                               "vnf_instance_description": "vRouter_test_description"
-                       }`)),
-                       expectedCode: http.StatusUnprocessableEntity,
-               },
-               {
-                       label: "Fail to get the VNF client",
-                       input: bytes.NewBuffer([]byte(`{
-                               "cloud_region_id": "region1",
-                               "rb-name": "test-rbdef",
-                               "rb-version": "v1",
-                               "profile-name": "profile1",
-                               "rb_profile_id": "123e4567-e89b-12d3-a456-426655440000",
-                               "csar_id": "UUID-1"
-                       }`)),
-                       expectedCode:        http.StatusInternalServerError,
-                       mockGetVNFClientErr: pkgerrors.New("Get VNF client error"),
-               },
-               {
-                       label: "Fail to create the VNF instance",
-                       input: bytes.NewBuffer([]byte(`{
-                               "cloud_region_id": "region1",
-                               "rb-name": "test-rbdef",
-                               "rb-version": "v1",
-                               "profile-name": "profile1",
-                               "rb_profile_id": "123e4567-e89b-12d3-a456-426655440000",
-                               "csar_id": "UUID-1"
-                       }`)),
-                       expectedCode: http.StatusInternalServerError,
-                       mockCreateVNF: &mockCSAR{
-                               err: pkgerrors.New("Internal error"),
-                       },
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       rb.ProfileKey{RBName: "testresourcebundle", RBVersion: "v1",
-                                               ProfileName: "profile1"}.String(): {
-                                               "metadata": []byte(
-                                                       "{\"profile-name\":\"profile1\"," +
-                                                               "\"release-name\":\"testprofilereleasename\"," +
-                                                               "\"namespace\":\"testnamespace\"," +
-                                                               "\"rb-name\":\"testresourcebundle\"," +
-                                                               "\"rb-version\":\"v1\"," +
-                                                               "\"kubernetesversion\":\"1.12.3\"}"),
-                                               // base64 encoding of vagrant/tests/vnfs/testrb/helm/profile
-                                               "content": []byte("H4sICLmjT1wAA3Byb2ZpbGUudGFyAO1Y32/bNhD2s/6Kg/KyYZZsy" +
-                                                       "78K78lLMsxY5gRxmqIYhoKWaJsYJWokZdfo+r/vSFmunCZNBtQJ1vF7sXX36e54vDN5T" +
-                                                       "knGFlTpcEtS3jgO2ohBr2c/EXc/29Gg1+h0e1F32Ol1B1Gj3Ymifr8B7SPFc4BCaSIBG" +
-                                                       "lII/SXeY/r/KIIg8NZUKiayEaw7nt7mdOQBrAkvqBqBL1ArWULflRJbJz4SYpEt2FJSJ" +
-                                                       "QoZ21cAAlgwTnOiVyPQWFQLwVuqmCdMthKac7FNaVZWmqWjkRWRuuSvScF1gFZVwYOEr" +
-                                                       "luapjknaOazd186Z98S7tver+3j0f5v1/q/18f+7w56bdf/zwFF5ZqV/WtbH6YioVdCa" +
-                                                       "hRkJEVBVSFBvUNRmyNpesgwors0lmkqM8KNzRG8iqLIWN45GUGv57l+fkFUP9PH9GF6f" +
-                                                       "IgH+kP9b76b/o+GUb9r5J1O1I0a0D9mUBX+5/1/55g+io9/sf+DnuF1sA4Gbv+fA1++p" +
-                                                       "n0dH4+c/92oPaztv+n/fn84dOf/c+AETkW+lWy50hC1O69gguc1R6HEw5xoHAuaKIq9E" +
-                                                       "+8ELvCikCmaQJElVIJeURjnJMaPnaYJt+UoAVHYhu8Mwd+p/O9/RAtbUUBKtnj+aygUR" +
-                                                       "RNM2ZkB6PuY5hpvCzhY4L2fkSymsGF6Zd3sjIRo4u3OhJhrgmyC/ByfFnUeEG0DLrHSO" +
-                                                       "h+1WpvNJiQ23FDIZYuXVNW6mJyeT2fnAYZsX3qdcaoUSPpXwSQudr4FkmNEMZljnJxsQ" +
-                                                       "EggOPmgTgsT8UYyzbJlE5RY6A2RFK0kTGnJ5oU+SFcVH666TsCEkQz88QwmMx9+Gs8ms" +
-                                                       "ybaeDO5+eXy9Q28GV9fj6c3k/MZXF7D6eX0bHIzuZzi088wnr6FXyfTsyZQTBa6oe9za" +
-                                                       "eLHIJlJJE1M1maUHgSwEGVAKqcxW7AY15UtC7KksDS3uQyXAzmVKVNmOxWGl6AVzlKmb" +
-                                                       "VGozxcVeh7J2W01S2LOVAsHyj9ZlozgbP+74qVUk4RoMtrfMD98wCzGvEiwXHD3U5GFi" +
-                                                       "4Jzo/QhhI8fd0yFu3c/fa/d8zmZU67KsRRDefCt/Qu7YdQSw1PzNTS3W1QGnyRVef+N5" +
-                                                       "YHDKZao/4MP/ju/siEpp0SVQYbX5UNlxxJwizCFyzuMWXkLNySzIyZs4wBrTpXE23I62" +
-                                                       "wlPRZHp0qJCC7EWslxpSnS8uqgt/YmLr2btnZXaDhnwA4NPzueT8lEt126AyExPY44rS" +
-                                                       "YA1bJPl15JgRaEdM9CKv/f1YDHdE5e1cYVFdiUwoduDJC+5mBMe5nstbndCF9Zfxakpa" +
-                                                       "1aNP2LK/Xffhuc3fTNfUYlfzH8a/h97qhmVaikNPi2+nItq8exGtLA+SdW9rgUvUvqbq" +
-                                                       "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" +
-                                                       "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA="),
-                                       },
-                                       rb.DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): {
-                                               "metadata": []byte(
-                                                       "{\"rb-name\":\"testresourcebundle\"," +
-                                                               "\"rb-version\":\"vault-consul-dev\"," +
-                                                               "\"chart-name\":\"vault-consul-dev\"," +
-                                                               "\"description\":\"testresourcebundle\"}"),
-                                               // base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev
-                                               "content": []byte("H4sICEetS1wAA3ZhdWx0LWNvbnN1bC1kZXYudGFyAO0c7XLbNjK/+R" +
-                                                       "QYujdJehatb+V4czPnOmnPk9bO2Gk7nbaTgUhIxpgiGAK0o3P9QPca92S3C5AU9GXZiax" +
-                                                       "c7rA/LJEAFovdxX4AK1/RIlGNSKSySBoxuzp4sn1oAgx6Pf0JsPipv7c63XZ70O61W4Mn" +
-                                                       "zVZ7MGg9Ib1HoGUJCqloTsiTXAh1V79N7V8oXC3K/+iC5iqY0kmytTlQwP1ud538W51Wf" +
-                                                       "0H+3QF8kObWKLgD/s/lv0eORDbN+fhCkXaz9YIcp4ol8DLPRE4VF+k+vIq8PW+PfM8jlk" +
-                                                       "oWkyKNWU7UBSOHGY3go2zZJz+xXMIY0g6a5Bl28Msm//lfAcNUFGRCpyQVihSSAQouyYg" +
-                                                       "njLAPEcsU4SmJxCRLOE0jRq65utDTlEgCQPFLiUIMFYXeFPpn8DSy+xGqNMEGLpTKwoOD" +
-                                                       "6+vrgGpyA5GPDxLTVR58f3z06uT8VQNI1oN+TBMmJcnZ+4LnsNjhlNAMKIroEOhM6DURO" +
-                                                       "aHjnEGbEkjxdc4VT8f7RIqRuqY5Aywxlyrnw0LNsauiD1ZtdwCG0ZT4h+fk+Nwn3xyeH5" +
-                                                       "/vA46fj9/+4/THt+Tnw7Ozw5O3x6/OyekZOTo9eXn89vj0BJ6+JYcnv5DXxycv9wkDZsE" +
-                                                       "07EOWI/1AJEdGshi5ds7YHAEjYQiSGYv4iEewrnRc0DEjY3HF8hSWQzKWT7hEcUogLwYs" +
-                                                       "CZ9wpZVCLi8q8Dya8VIBQnLV8mImo5xnSj9ru4IMS2iRRhfkJzQ8iJcY44OMBPtDJiJmX" +
-                                                       "konDFAs2CbAn9X4m8Ffgp53VT2C9EB+n3s3fXmwZP+vaFIwuVUHsMH+d1vd3oL977X6TW" +
-                                                       "f/dwHO/jv7vzX7v/epAHN8l4ghTdApjPi4MCoIjmGEdkoGW5hirCcIPQJaGLM3Ildvcjb" +
-                                                       "iH0LSabbhbYYqLBUDBQzJzS2sqpK/JoVPgEue/os4jOUMq88WuKE+vNZmtfRgYTNooXPK" +
-                                                       "iiR5IwDRNCSHyTWdSsQ9SugY9YilWr9iNizGY2R/Y25aWWSwIVWtlp7u+EoPikMyoolk2" +
-                                                       "xHAoTXr40nBYLY46OFWlSwH7QuJygumXyRi/C5hVww4fHzy7enqTjFV9F3M4dXTA4PtAF" +
-                                                       "891Y3INWmwl6aAvOg1m9YLGZJGy6uFZuZQYP2MhBFsGhFoHOMmC4G+iCYXQqrQQgqTUnV" +
-                                                       "RSt8sQysUEF32UFG2AtnTX8Pw9/BFu9l8WjeqRMLSJIrZXrF5824C81+W79HoGAGRtJgM" +
-                                                       "YXOCUeQpuDfQZOnlTIv1SBQpKCasF7X/nCUsgqUaRaejEU+5mlZqn+ViyBZ0IKM5xGYK9" +
-                                                       "oiX8CtYk9TMxXGcJi9ZQqfnDIbEsJ5W02wnLuL5d3skZUCTpPkUVb9cDakQlhNfXzDQe6" +
-                                                       "bQtpJhzuhlJniqpEago0XcKrBOKcjrF2BRBZPpU9wi6NLBwaTwLQPJAVpcBfoLlsNoVu0" +
-                                                       "awzfAHPOPWYhnm4olvKBPIikm7IxFCeWTauefMaQDWmmELPgBpIAvafwzeBF2CqigTfJ/" +
-                                                       "wtv2dxy+T1Bib7RCHcQgbpajcjfSkawaz4uhaZcTaW8Az8Otwg1xapoBypPS5KH1W4qxP" +
-                                                       "bNbTlY1AOPBLdAEB8MOamtlrwxoSLpdzwMx5SUX2bxd+txBjoO1sBT/KwZRA1UQGG1tjo" +
-                                                       "ef/3UH/YE7/9sF3CH/GDyGmE5Y+qnHgZvyv2Z7MC9/sC6dvsv/dgF7Lv9z+d9jnP8Bz+T" +
-                                                       "BVcu75CnEAS9rW+JB9EgxOgnrGOTmBrgYJUUM6gLSn4g0GEGuhI0+CcjtbdlTgvRWd69b" +
-                                                       "6/4JHbKkjPuBlLWj6gEQ5OMJpe4YmEsQDISgsTF7U6n3HwTDaZiP+H/2if/Or3DkEFBTa" +
-                                                       "YgMzsxDhUd3ABEBC8cLPc5NnIadUCJIdhmvS9PxJ3MqZwfxBqOsIniNfUJVdPG9tfR7Lr" +
-                                                       "4y+iUWS0I6e5lDeG9+3osf1XLLLMvE6PVcDZNuh8S3mKBfBdpxARa/nmutMq2gS+N4YyX" +
-                                                       "kFn5zQBDM0nUQd5VZVX2sRgsrzkdR3X/1NXn+vm+SVfiCztX/fZYh2mkpLrRevAmoLXrK" +
-                                                       "ID6wQ3B7VpNm/IA6MYfRThyYig50rqr4hNV9Kp6tasGs6DRNplWWtFEg5TH+AyXSGFJIa" +
-                                                       "cC67Ewyhk6QCMyTqntIxqwCvYjFngVxzWX/OxGIPdUKcldhwHMKPb31rjqrWCDoc4clDn" +
-                                                       "YEd8T/ld355KugDfF/u99avP8ZdNz9/27Axf8u/n+s+38T+pex7f3i/tLmPHrov5Rf/Le" +
-                                                       "F/+a4dkUUiA0GWx2oNGb8XOxdnedW89/c8BFh71dj9avTYZ80yv7ZQ4LR2XHwcsw2f9dm" +
-                                                       "xW1+p9lG/q2YoxozI75BQLJsM3XswzJ1YObHTD0outYTpnE1Wy6UiEQSkrdHb5ZSr3smR" +
-                                                       "XdqyGew/0v+X2+DLR7+Pvmo8982dHfnvzuAdfI32rsdNXi4/Hu9rpP/TmCD/LdSDbwh/m" +
-                                                       "+1+93F+L876Ln4fxdgx////hemAANyOIlFJPfJNyyBTICmELa5+N/F/59Y/6sNSn3SLDU" +
-                                                       "JOljSCgNsFJp+Y3/KCmBjhVyV7+PBBvu/lWrgjec/gyX7P+i2nP3fBTj77+z/F1P/S4w5" +
-                                                       "glmpIhGwbAisTPWZihYUluqCyspiaKzYdsuF9/A3LCmwCKQOcxdpgXtBV+Vm5lQjr5rh+" +
-                                                       "YqlyjTiUkB9ysJFrdPG1dXFmSQvUs1ybASF0pLBM4HLF5Kgh1S6bnFVvbIphsQ7MzyTEp" +
-                                                       "IrkXMmzQWyeZyGJGUfCtkJREozVP6whWG3GVtXP4LnZdGlR2ZvziwMQkyAGLv12FwE1s8" +
-                                                       "NPT40LlqjToSpZNYXbR6pnm20pqAxYAmVikdBJGbdSvxDRsEdoY3Ab2Ev6FXozarxvg/4" +
-                                                       "jBd+eCa2osYa+1YKpK/g9JUXQYMOuzDXZzhTWMeI5VjJGesBsOvr6k5VXbPpnysBedpky" +
-                                                       "YVacXN1vr5YU6P92GpvQubrvfUV4Dbs/wb/v5VqwIfn/4Net+Py/13AveX/rj5oD1T2sG" +
-                                                       "BwU/7f73cW6v/anb7L/3cCNzcHX3suCHRB4LaCwK8Pbm89T6sVIWdMiuTKzFrbDx0/ATP" +
-                                                       "1bz+oSfgD8vaCzX6/UneVxQhCHfz9gayRVHKuB0JbGQwi2TmPY5YSPrJ+ZPKMjQO93Do0" +
-                                                       "fA44C4krRFQjkSTiGp90hBl6+latuiJKZXlrRcJqBns5JvgzC8cbI1gFBESrLijNvVXZx" +
-                                                       "1Qt2VdABt3SrI0SL4Pgo7HtW6L72/9ZPPlQB7DB/nc6ve6i/e93Xf3HTsDZf2f/d2f/a9" +
-                                                       "NtDoMX8tZpAEPQD2gjrMmzCp/LPsg2nXiDSEoruo+23AisXH9tpScM7FnK5aQaFsyb9rI" +
-                                                       "6wUJv2/jKSi/SqUnDkwbdIOcwznqdVmgsjGY+nUeuRY6KgHwvW4YUUsy13mU2buZewPXd" +
-                                                       "QY1V25DlPFUj4v9J+neNqPBi7YU1erHy1lrCevbWuHRZhe3WVirNEnMki3KG/0fkkqXr1" +
-                                                       "WVp3iPcxKUKhHOHI9hicndoy0P915R7UCmvRQ7JdvWtLLHnSUgYfpBnQl9u0OT5PeQTGN" +
-                                                       "LtKOArbCXh35aKRmyplqUjun+Ey4D+d69z1l9TCf3rYpu/+wZJoFtmHWkBRhY6zjQiRKU" +
-                                                       "wfZEl5deKFeQPMux3WRrNcFRDb36D0b/5IXziQNz28GRe7v/mVxjsd5qb9gskp36+vfVL" +
-                                                       "Tq0nx6zULKMm7VEDp/8RuH/8V5eKPTD733z/01zO/6G/i/92AS7+c/HfbuO/MuN/KkllU" +
-                                                       "bzSj1de6pqDyg3ZLMk3Y59ZDh5f1PEJxDuSqecYDhyCqcdhqFditFxRqmkox0kM4Rbiwb" +
-                                                       "mOq0LBsgN5xllgiHuuqasCAL3sVx8yWhJS9dcIddhYnlusjRjmSqCtWEFjsHy5XaW8ki3" +
-                                                       "Lpw0Gx8q1/oFXCuAz+x39lU/O9ckL8Rv+oh/93CbLwRbhYef/H+H8n2z2/612e8H/w5P7" +
-                                                       "/287Aef/nf9/PP9vOcIF97/e/y06vnv7uwe4sJpAyJfBugFR1Sz4w6ApeV/QBDgCUrFv5" +
-                                                       "bUFxFgFp6EoM6pwNlyQhIAloqjOUgCBr4shMJBhnaPx/JwlMXAwZ4Z/Rm205j8D3UIGvQ" +
-                                                       "RZQl9kOgrk+XoOzX68tJ3wYJb0N/RJ0NzPUr5y4YEDBw4cOHDgwIEDBw4cOHDgwIEDBw4" +
-                                                       "cOHDgwIEDB18K/AcxEDJDAHgAAA=="),
-                                       },
-                               },
-                       },
-               },
-               {
-                       label: "Fail to create a VNF DB record",
-                       input: bytes.NewBuffer([]byte(`{
-                               "cloud_region_id": "region1",
-                               "rb-name": "test-rbdef",
-                               "rb-version": "v1",
-                               "profile-name": "profile1",
-                               "rb_profile_id": "123e4567-e89b-12d3-a456-426655440000",
-                               "csar_id": "UUID-1"
-                       }`)),
-                       expectedCode: http.StatusInternalServerError,
-                       mockCreateVNF: &mockCSAR{
-                               resourceYAMLNameMap: map[string][]string{},
-                       },
-                       mockStore: &db.MockDB{
-                               Err: pkgerrors.New("Internal error"),
-                       },
-               },
-               {
-                       label: "Succesful create a VNF",
-                       input: bytes.NewBuffer([]byte(`{
-                               "cloud_region_id": "region1",
-                               "rb-name": "test-rbdef",
-                               "rb-version": "v1",
-                               "profile-name": "profile1",
-                               "rb_profile_id": "123e4567-e89b-12d3-a456-426655440000",
-                               "csar_id": "UUID-1"
-                       }`)),
-                       expectedCode: http.StatusCreated,
-                       mockCreateVNF: &mockCSAR{
-                               resourceYAMLNameMap: map[string][]string{
-                                       "deployment": []string{"cloud1-default-uuid-sisedeploy"},
-                                       "service":    []string{"cloud1-default-uuid-sisesvc"},
-                               },
-                       },
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       rb.ProfileKey{RBName: "test-rbdef", RBVersion: "v1",
-                                               ProfileName: "profile1"}.String(): {
-                                               "metadata": []byte(
-                                                       "{\"profile-name\":\"profile1\"," +
-                                                               "\"release-name\":\"testprofilereleasename\"," +
-                                                               "\"namespace\":\"testnamespace\"," +
-                                                               "\"rb-name\":\"test-rbdef\"," +
-                                                               "\"rb-version\":\"v1\"," +
-                                                               "\"kubernetesversion\":\"1.12.3\"}"),
-                                               // base64 encoding of vagrant/tests/vnfs/testrb/helm/profile
-                                               "content": []byte("H4sICLmjT1wAA3Byb2ZpbGUudGFyAO1Y32/bNhD2s/6Kg/KyYZZsy" +
-                                                       "78K78lLMsxY5gRxmqIYhoKWaJsYJWokZdfo+r/vSFmunCZNBtQJ1vF7sXX36e54vDN5T" +
-                                                       "knGFlTpcEtS3jgO2ohBr2c/EXc/29Gg1+h0e1F32Ol1B1Gj3Ymifr8B7SPFc4BCaSIBG" +
-                                                       "lII/SXeY/r/KIIg8NZUKiayEaw7nt7mdOQBrAkvqBqBL1ArWULflRJbJz4SYpEt2FJSJ" +
-                                                       "QoZ21cAAlgwTnOiVyPQWFQLwVuqmCdMthKac7FNaVZWmqWjkRWRuuSvScF1gFZVwYOEr" +
-                                                       "luapjknaOazd186Z98S7tver+3j0f5v1/q/18f+7w56bdf/zwFF5ZqV/WtbH6YioVdCa" +
-                                                       "hRkJEVBVSFBvUNRmyNpesgwors0lmkqM8KNzRG8iqLIWN45GUGv57l+fkFUP9PH9GF6f" +
-                                                       "IgH+kP9b76b/o+GUb9r5J1O1I0a0D9mUBX+5/1/55g+io9/sf+DnuF1sA4Gbv+fA1++p" +
-                                                       "n0dH4+c/92oPaztv+n/fn84dOf/c+AETkW+lWy50hC1O69gguc1R6HEw5xoHAuaKIq9E" +
-                                                       "+8ELvCikCmaQJElVIJeURjnJMaPnaYJt+UoAVHYhu8Mwd+p/O9/RAtbUUBKtnj+aygUR" +
-                                                       "RNM2ZkB6PuY5hpvCzhY4L2fkSymsGF6Zd3sjIRo4u3OhJhrgmyC/ByfFnUeEG0DLrHSO" +
-                                                       "h+1WpvNJiQ23FDIZYuXVNW6mJyeT2fnAYZsX3qdcaoUSPpXwSQudr4FkmNEMZljnJxsQ" +
-                                                       "EggOPmgTgsT8UYyzbJlE5RY6A2RFK0kTGnJ5oU+SFcVH666TsCEkQz88QwmMx9+Gs8ms" +
-                                                       "ybaeDO5+eXy9Q28GV9fj6c3k/MZXF7D6eX0bHIzuZzi088wnr6FXyfTsyZQTBa6oe9za" +
-                                                       "eLHIJlJJE1M1maUHgSwEGVAKqcxW7AY15UtC7KksDS3uQyXAzmVKVNmOxWGl6AVzlKmb" +
-                                                       "VGozxcVeh7J2W01S2LOVAsHyj9ZlozgbP+74qVUk4RoMtrfMD98wCzGvEiwXHD3U5GFi" +
-                                                       "4Jzo/QhhI8fd0yFu3c/fa/d8zmZU67KsRRDefCt/Qu7YdQSw1PzNTS3W1QGnyRVef+N5" +
-                                                       "YHDKZao/4MP/ju/siEpp0SVQYbX5UNlxxJwizCFyzuMWXkLNySzIyZs4wBrTpXE23I62" +
-                                                       "wlPRZHp0qJCC7EWslxpSnS8uqgt/YmLr2btnZXaDhnwA4NPzueT8lEt126AyExPY44rS" +
-                                                       "YA1bJPl15JgRaEdM9CKv/f1YDHdE5e1cYVFdiUwoduDJC+5mBMe5nstbndCF9Zfxakpa" +
-                                                       "1aNP2LK/Xffhuc3fTNfUYlfzH8a/h97qhmVaikNPi2+nItq8exGtLA+SdW9rgUvUvqbq" +
-                                                       "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" +
-                                                       "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA="),
-                                       },
-                                       rb.DefinitionKey{Name: "test-rbdef", Version: "v1"}.String(): {
-                                               "metadata": []byte(
-                                                       "{\"rb-name\":\"test-rbdef\"," +
-                                                               "\"rb-version\":\"v1\"," +
-                                                               "\"chart-name\":\"vault-consul-dev\"," +
-                                                               "\"description\":\"testresourcebundle\"}"),
-                                               // base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev
-                                               "content": []byte("H4sICEetS1wAA3ZhdWx0LWNvbnN1bC1kZXYudGFyAO0c7XLbNjK/+R" +
-                                                       "QYujdJehatb+V4czPnOmnPk9bO2Gk7nbaTgUhIxpgiGAK0o3P9QPca92S3C5AU9GXZiax" +
-                                                       "c7rA/LJEAFovdxX4AK1/RIlGNSKSySBoxuzp4sn1oAgx6Pf0JsPipv7c63XZ70O61W4Mn" +
-                                                       "zVZ7MGg9Ib1HoGUJCqloTsiTXAh1V79N7V8oXC3K/+iC5iqY0kmytTlQwP1ud538W51Wf" +
-                                                       "0H+3QF8kObWKLgD/s/lv0eORDbN+fhCkXaz9YIcp4ol8DLPRE4VF+k+vIq8PW+PfM8jlk" +
-                                                       "oWkyKNWU7UBSOHGY3go2zZJz+xXMIY0g6a5Bl28Msm//lfAcNUFGRCpyQVihSSAQouyYg" +
-                                                       "njLAPEcsU4SmJxCRLOE0jRq65utDTlEgCQPFLiUIMFYXeFPpn8DSy+xGqNMEGLpTKwoOD" +
-                                                       "6+vrgGpyA5GPDxLTVR58f3z06uT8VQNI1oN+TBMmJcnZ+4LnsNjhlNAMKIroEOhM6DURO" +
-                                                       "aHjnEGbEkjxdc4VT8f7RIqRuqY5Aywxlyrnw0LNsauiD1ZtdwCG0ZT4h+fk+Nwn3xyeH5" +
-                                                       "/vA46fj9/+4/THt+Tnw7Ozw5O3x6/OyekZOTo9eXn89vj0BJ6+JYcnv5DXxycv9wkDZsE" +
-                                                       "07EOWI/1AJEdGshi5ds7YHAEjYQiSGYv4iEewrnRc0DEjY3HF8hSWQzKWT7hEcUogLwYs" +
-                                                       "CZ9wpZVCLi8q8Dya8VIBQnLV8mImo5xnSj9ru4IMS2iRRhfkJzQ8iJcY44OMBPtDJiJmX" +
-                                                       "konDFAs2CbAn9X4m8Ffgp53VT2C9EB+n3s3fXmwZP+vaFIwuVUHsMH+d1vd3oL977X6TW" +
-                                                       "f/dwHO/jv7vzX7v/epAHN8l4ghTdApjPi4MCoIjmGEdkoGW5hirCcIPQJaGLM3Ildvcjb" +
-                                                       "iH0LSabbhbYYqLBUDBQzJzS2sqpK/JoVPgEue/os4jOUMq88WuKE+vNZmtfRgYTNooXPK" +
-                                                       "iiR5IwDRNCSHyTWdSsQ9SugY9YilWr9iNizGY2R/Y25aWWSwIVWtlp7u+EoPikMyoolk2" +
-                                                       "xHAoTXr40nBYLY46OFWlSwH7QuJygumXyRi/C5hVww4fHzy7enqTjFV9F3M4dXTA4PtAF" +
-                                                       "891Y3INWmwl6aAvOg1m9YLGZJGy6uFZuZQYP2MhBFsGhFoHOMmC4G+iCYXQqrQQgqTUnV" +
-                                                       "RSt8sQysUEF32UFG2AtnTX8Pw9/BFu9l8WjeqRMLSJIrZXrF5824C81+W79HoGAGRtJgM" +
-                                                       "YXOCUeQpuDfQZOnlTIv1SBQpKCasF7X/nCUsgqUaRaejEU+5mlZqn+ViyBZ0IKM5xGYK9" +
-                                                       "oiX8CtYk9TMxXGcJi9ZQqfnDIbEsJ5W02wnLuL5d3skZUCTpPkUVb9cDakQlhNfXzDQe6" +
-                                                       "bQtpJhzuhlJniqpEago0XcKrBOKcjrF2BRBZPpU9wi6NLBwaTwLQPJAVpcBfoLlsNoVu0" +
-                                                       "awzfAHPOPWYhnm4olvKBPIikm7IxFCeWTauefMaQDWmmELPgBpIAvafwzeBF2CqigTfJ/" +
-                                                       "wtv2dxy+T1Bib7RCHcQgbpajcjfSkawaz4uhaZcTaW8Az8Otwg1xapoBypPS5KH1W4qxP" +
-                                                       "bNbTlY1AOPBLdAEB8MOamtlrwxoSLpdzwMx5SUX2bxd+txBjoO1sBT/KwZRA1UQGG1tjo" +
-                                                       "ef/3UH/YE7/9sF3CH/GDyGmE5Y+qnHgZvyv2Z7MC9/sC6dvsv/dgF7Lv9z+d9jnP8Bz+T" +
-                                                       "BVcu75CnEAS9rW+JB9EgxOgnrGOTmBrgYJUUM6gLSn4g0GEGuhI0+CcjtbdlTgvRWd69b" +
-                                                       "6/4JHbKkjPuBlLWj6gEQ5OMJpe4YmEsQDISgsTF7U6n3HwTDaZiP+H/2if/Or3DkEFBTa" +
-                                                       "YgMzsxDhUd3ABEBC8cLPc5NnIadUCJIdhmvS9PxJ3MqZwfxBqOsIniNfUJVdPG9tfR7Lr" +
-                                                       "4y+iUWS0I6e5lDeG9+3osf1XLLLMvE6PVcDZNuh8S3mKBfBdpxARa/nmutMq2gS+N4YyX" +
-                                                       "kFn5zQBDM0nUQd5VZVX2sRgsrzkdR3X/1NXn+vm+SVfiCztX/fZYh2mkpLrRevAmoLXrK" +
-                                                       "ID6wQ3B7VpNm/IA6MYfRThyYig50rqr4hNV9Kp6tasGs6DRNplWWtFEg5TH+AyXSGFJIa" +
-                                                       "cC67Ewyhk6QCMyTqntIxqwCvYjFngVxzWX/OxGIPdUKcldhwHMKPb31rjqrWCDoc4clDn" +
-                                                       "YEd8T/ld355KugDfF/u99avP8ZdNz9/27Axf8u/n+s+38T+pex7f3i/tLmPHrov5Rf/Le" +
-                                                       "F/+a4dkUUiA0GWx2oNGb8XOxdnedW89/c8BFh71dj9avTYZ80yv7ZQ4LR2XHwcsw2f9dm" +
-                                                       "xW1+p9lG/q2YoxozI75BQLJsM3XswzJ1YObHTD0outYTpnE1Wy6UiEQSkrdHb5ZSr3smR" +
-                                                       "XdqyGew/0v+X2+DLR7+Pvmo8982dHfnvzuAdfI32rsdNXi4/Hu9rpP/TmCD/LdSDbwh/m" +
-                                                       "+1+93F+L876Ln4fxdgx////hemAANyOIlFJPfJNyyBTICmELa5+N/F/59Y/6sNSn3SLDU" +
-                                                       "JOljSCgNsFJp+Y3/KCmBjhVyV7+PBBvu/lWrgjec/gyX7P+i2nP3fBTj77+z/F1P/S4w5" +
-                                                       "glmpIhGwbAisTPWZihYUluqCyspiaKzYdsuF9/A3LCmwCKQOcxdpgXtBV+Vm5lQjr5rh+" +
-                                                       "YqlyjTiUkB9ysJFrdPG1dXFmSQvUs1ybASF0pLBM4HLF5Kgh1S6bnFVvbIphsQ7MzyTEp" +
-                                                       "IrkXMmzQWyeZyGJGUfCtkJREozVP6whWG3GVtXP4LnZdGlR2ZvziwMQkyAGLv12FwE1s8" +
-                                                       "NPT40LlqjToSpZNYXbR6pnm20pqAxYAmVikdBJGbdSvxDRsEdoY3Ab2Ev6FXozarxvg/4" +
-                                                       "jBd+eCa2osYa+1YKpK/g9JUXQYMOuzDXZzhTWMeI5VjJGesBsOvr6k5VXbPpnysBedpky" +
-                                                       "YVacXN1vr5YU6P92GpvQubrvfUV4Dbs/wb/v5VqwIfn/4Net+Py/13AveX/rj5oD1T2sG" +
-                                                       "BwU/7f73cW6v/anb7L/3cCNzcHX3suCHRB4LaCwK8Pbm89T6sVIWdMiuTKzFrbDx0/ATP" +
-                                                       "1bz+oSfgD8vaCzX6/UneVxQhCHfz9gayRVHKuB0JbGQwi2TmPY5YSPrJ+ZPKMjQO93Do0" +
-                                                       "fA44C4krRFQjkSTiGp90hBl6+latuiJKZXlrRcJqBns5JvgzC8cbI1gFBESrLijNvVXZx" +
-                                                       "1Qt2VdABt3SrI0SL4Pgo7HtW6L72/9ZPPlQB7DB/nc6ve6i/e93Xf3HTsDZf2f/d2f/a9" +
-                                                       "NtDoMX8tZpAEPQD2gjrMmzCp/LPsg2nXiDSEoruo+23AisXH9tpScM7FnK5aQaFsyb9rI" +
-                                                       "6wUJv2/jKSi/SqUnDkwbdIOcwznqdVmgsjGY+nUeuRY6KgHwvW4YUUsy13mU2buZewPXd" +
-                                                       "QY1V25DlPFUj4v9J+neNqPBi7YU1erHy1lrCevbWuHRZhe3WVirNEnMki3KG/0fkkqXr1" +
-                                                       "WVp3iPcxKUKhHOHI9hicndoy0P915R7UCmvRQ7JdvWtLLHnSUgYfpBnQl9u0OT5PeQTGN" +
-                                                       "LtKOArbCXh35aKRmyplqUjun+Ey4D+d69z1l9TCf3rYpu/+wZJoFtmHWkBRhY6zjQiRKU" +
-                                                       "wfZEl5deKFeQPMux3WRrNcFRDb36D0b/5IXziQNz28GRe7v/mVxjsd5qb9gskp36+vfVL" +
-                                                       "Tq0nx6zULKMm7VEDp/8RuH/8V5eKPTD733z/01zO/6G/i/92AS7+c/HfbuO/MuN/KkllU" +
-                                                       "bzSj1de6pqDyg3ZLMk3Y59ZDh5f1PEJxDuSqecYDhyCqcdhqFditFxRqmkox0kM4Rbiwb" +
-                                                       "mOq0LBsgN5xllgiHuuqasCAL3sVx8yWhJS9dcIddhYnlusjRjmSqCtWEFjsHy5XaW8ki3" +
-                                                       "Lpw0Gx8q1/oFXCuAz+x39lU/O9ckL8Rv+oh/93CbLwRbhYef/H+H8n2z2/612e8H/w5P7" +
-                                                       "/287Aef/nf9/PP9vOcIF97/e/y06vnv7uwe4sJpAyJfBugFR1Sz4w6ApeV/QBDgCUrFv5" +
-                                                       "bUFxFgFp6EoM6pwNlyQhIAloqjOUgCBr4shMJBhnaPx/JwlMXAwZ4Z/Rm205j8D3UIGvQ" +
-                                                       "RZQl9kOgrk+XoOzX68tJ3wYJb0N/RJ0NzPUr5y4YEDBw4cOHDgwIEDBw4cOHDgwIEDBw4" +
-                                                       "cOHDgwIEDB18K/AcxEDJDAHgAAA=="),
-                                       },
-                               },
-                       },
-               },
-       }
-
-       for _, testCase := range testCases {
-               t.Run(testCase.label, func(t *testing.T) {
-                       GetVNFClient = func(configPath string) (kubernetes.Clientset, error) {
-                               return kubernetes.Clientset{}, testCase.mockGetVNFClientErr
-                       }
-                       if testCase.mockCreateVNF != nil {
-                               helper.CreateVNF = testCase.mockCreateVNF.CreateVNF
-                       }
-                       if testCase.mockStore != nil {
-                               db.DBconn = testCase.mockStore
-                       }
-
-                       request := httptest.NewRequest("POST", "/v1/vnf_instances/", testCase.input)
-                       result := executeRequest(request)
-
-                       if testCase.expectedCode != result.StatusCode {
-                               t.Fatalf("Request method returned: \n%v\n and it was expected: \n%v", result.StatusCode, testCase.expectedCode)
-                       }
-                       if result.StatusCode == http.StatusCreated {
-                               var response CreateVnfResponse
-                               err := json.NewDecoder(result.Body).Decode(&response)
-                               if err != nil {
-                                       t.Fatalf("Parsing the returned response got an error (%s)", err)
-                               }
-                       }
-               })
-       }
-}
-
-func TestListHandler(t *testing.T) {
-       testCases := []struct {
-               label            string
-               expectedCode     int
-               expectedResponse []string
-               mockStore        *db.MockDB
-       }{
-               {
-                       label:        "Fail to retrieve DB records",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Err: pkgerrors.New("Internal error"),
-                       },
-               },
-               {
-                       label:            "Get empty list",
-                       expectedCode:     http.StatusOK,
-                       expectedResponse: []string{""},
-                       mockStore:        &db.MockDB{},
-               },
-               {
-                       label:            "Succesful get a list of VNF",
-                       expectedCode:     http.StatusOK,
-                       expectedResponse: []string{"uid1"},
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "uuid1": {
-                                               "data": []byte("{}"),
-                                       },
-                               },
-                       },
-               },
-       }
-
-       for _, testCase := range testCases {
-               t.Run(testCase.label, func(t *testing.T) {
-                       if testCase.mockStore != nil {
-                               db.DBconn = testCase.mockStore
-                       }
-
-                       request := httptest.NewRequest("GET", "/v1/vnf_instances/cloud1/default", nil)
-                       result := executeRequest(request)
-
-                       if testCase.expectedCode != result.StatusCode {
-                               t.Fatalf("Request method returned: \n%v\n and it was expected: \n%v",
-                                       result.StatusCode, testCase.expectedCode)
-                       }
-                       if result.StatusCode == http.StatusOK {
-                               var response ListVnfsResponse
-                               err := json.NewDecoder(result.Body).Decode(&response)
-                               if err != nil {
-                                       t.Fatalf("Parsing the returned response got an error (%s)", err)
-                               }
-                               if !reflect.DeepEqual(testCase.expectedResponse, response.VNFs) {
-                                       t.Fatalf("TestListHandler returned:\n result=%v\n expected=%v",
-                                               response.VNFs, testCase.expectedResponse)
-                               }
-                       }
-               })
-       }
-}
-
-func TestDeleteHandler(t *testing.T) {
-       testCases := []struct {
-               label               string
-               expectedCode        int
-               mockGetVNFClientErr error
-               mockDeleteVNF       *mockCSAR
-               mockStore           *db.MockDB
-       }{
-               {
-                       label:        "Fail to read a VNF DB record",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Err: pkgerrors.New("Internal error"),
-                       },
-               },
-               {
-                       label:        "Fail to find VNF record be deleted",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{},
-                       },
-               },
-               {
-                       label:        "Fail to unmarshal the DB record",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloudregion1-testnamespace-uuid1": {
-                                               "data": []byte("{invalid format}"),
-                                       },
-                               },
-                       },
-               },
-               {
-                       label:               "Fail to get the VNF client",
-                       expectedCode:        http.StatusInternalServerError,
-                       mockGetVNFClientErr: pkgerrors.New("Get VNF client error"),
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloudregion1-testnamespace-uuid1": {
-                                               "data": []byte(
-                                                       "{\"deployment\": [\"deploy1\", \"deploy2\"]," +
-                                                               "\"service\": [\"svc1\", \"svc2\"]}"),
-                                       },
-                               },
-                       },
-               },
-               {
-                       label:        "Fail to destroy VNF",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloudregion1-testnamespace-uuid1": {
-                                               "data": []byte(
-                                                       "{\"deployment\": [\"deploy1\", \"deploy2\"]," +
-                                                               "\"service\": [\"svc1\", \"svc2\"]}"),
-                                       },
-                               },
-                       },
-                       mockDeleteVNF: &mockCSAR{
-                               err: pkgerrors.New("Internal error"),
-                       },
-               },
-               {
-                       label:        "Succesful delete a VNF",
-                       expectedCode: http.StatusAccepted,
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloudregion1-testnamespace-uuid1": {
-                                               "data": []byte(
-                                                       "{\"deployment\": [\"deploy1\", \"deploy2\"]," +
-                                                               "\"service\": [\"svc1\", \"svc2\"]}"),
-                                       },
-                               },
-                       },
-                       mockDeleteVNF: &mockCSAR{},
-               },
-       }
-
-       for _, testCase := range testCases {
-               t.Run(testCase.label, func(t *testing.T) {
-                       GetVNFClient = func(configPath string) (kubernetes.Clientset, error) {
-                               return kubernetes.Clientset{}, testCase.mockGetVNFClientErr
-                       }
-                       if testCase.mockStore != nil {
-                               db.DBconn = testCase.mockStore
-                       }
-                       if testCase.mockDeleteVNF != nil {
-                               helper.DestroyVNF = testCase.mockDeleteVNF.DestroyVNF
-                       }
-
-                       request := httptest.NewRequest("DELETE", "/v1/vnf_instances/cloudregion1/testnamespace/uuid1", nil)
-                       result := executeRequest(request)
-
-                       if testCase.expectedCode != result.StatusCode {
-                               t.Fatalf("Request method returned: %v and it was expected: %v", result.StatusCode, testCase.expectedCode)
-                       }
-               })
-       }
-}
-
-// TODO: Update this test when the UpdateVNF endpoint is fixed.
-/*
-func TestVNFInstanceUpdate(t *testing.T) {
-       t.Run("Succesful update a VNF", func(t *testing.T) {
-               payload := []byte(`{
-                       "cloud_region_id": "region1",
-                       "csar_id": "UUID-1",
-                       "oof_parameters": [{
-                               "key1": "value1",
-                               "key2": "value2",
-                               "key3": {}
-                       }],
-                       "network_parameters": {
-                               "oam_ip_address": {
-                                       "connection_point": "string",
-                                       "ip_address": "string",
-                                       "workload_name": "string"
-                               }
-                       }
-               }`)
-               expected := &UpdateVnfResponse{
-                       DeploymentID: "1",
-               }
-
-               var result UpdateVnfResponse
-
-               req := httptest.NewRequest("PUT", "/v1/vnf_instances/1", bytes.NewBuffer(payload))
-
-               GetVNFClient = func(configPath string) (krd.VNFInstanceClientInterface, error) {
-                       return &mockClient{
-                               update: func() error {
-                                       return nil
-                               },
-                       }, nil
-               }
-               utils.ReadCSARFromFileSystem = func(csarID string) (*krd.KubernetesData, error) {
-                       kubeData := &krd.KubernetesData{
-                               Deployment: &appsV1.Deployment{},
-                               Service:    &coreV1.Service{},
-                       }
-                       return kubeData, nil
-               }
-
-               response := executeRequest(req)
-               checkResponseCode(t, http.StatusCreated, response.Code)
-
-               err := json.NewDecoder(response.Body).Decode(&result)
-               if err != nil {
-                       t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", err, expected.DeploymentID)
-               }
-
-               if result.DeploymentID != expected.DeploymentID {
-                       t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", result.DeploymentID, expected.DeploymentID)
-               }
-       })
-}
-*/
-
-func TestGetHandler(t *testing.T) {
-       testCases := []struct {
-               label            string
-               expectedCode     int
-               expectedResponse *GetVnfResponse
-               mockStore        *db.MockDB
-       }{
-               {
-                       label:        "Fail to retrieve DB record",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Err: pkgerrors.New("Internal error"),
-                       },
-               },
-               {
-                       label:        "Not found DB record",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore:    &db.MockDB{},
-               },
-               {
-                       label:        "Fail to unmarshal the DB record",
-                       expectedCode: http.StatusInternalServerError,
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloud1-default-1": {
-                                               "data": []byte("{invalid-format}"),
-                                       },
-                               },
-                       },
-               },
-               {
-                       label:        "Succesful get a list of VNF",
-                       expectedCode: http.StatusOK,
-                       expectedResponse: &GetVnfResponse{
-                               VNFID:         "1",
-                               CloudRegionID: "cloud1",
-                               Namespace:     "default",
-                               VNFComponents: map[string][]string{
-                                       "deployment": []string{"deploy1", "deploy2"},
-                                       "service":    []string{"svc1", "svc2"},
-                               },
-                       },
-                       mockStore: &db.MockDB{
-                               Items: map[string]map[string][]byte{
-                                       "cloud1-default-1": {
-                                               "data": []byte(
-                                                       "{\"deployment\": [\"deploy1\", \"deploy2\"]," +
-                                                               "\"service\": [\"svc1\", \"svc2\"]}"),
-                                               "cloud1-default-2": []byte("{}"),
-                                       },
-                               },
-                       },
-               },
-       }
-
-       for _, testCase := range testCases {
-               t.Run(testCase.label, func(t *testing.T) {
-                       db.DBconn = testCase.mockStore
-                       request := httptest.NewRequest("GET", "/v1/vnf_instances/cloud1/default/1", nil)
-                       result := executeRequest(request)
-
-                       if testCase.expectedCode != result.StatusCode {
-                               t.Fatalf("Request method returned: %v and it was expected: %v",
-                                       result.StatusCode, testCase.expectedCode)
-                       }
-                       if result.StatusCode == http.StatusOK {
-                               var response GetVnfResponse
-                               err := json.NewDecoder(result.Body).Decode(&response)
-                               if err != nil {
-                                       t.Fatalf("Parsing the returned response got an error (%s)", err)
-                               }
-                               if !reflect.DeepEqual(testCase.expectedResponse, &response) {
-                                       t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
-                                               &response, testCase.expectedResponse)
-                               }
-                       }
-               })
-       }
-}
diff --git a/src/k8splugin/api/instancehandler.go b/src/k8splugin/api/instancehandler.go
new file mode 100644 (file)
index 0000000..4fc3cfc
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+Copyright 2018 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 api
+
+import (
+       "encoding/json"
+       "errors"
+       "io"
+       "net/http"
+
+       "k8splugin/internal/app"
+
+       "github.com/gorilla/mux"
+       pkgerrors "github.com/pkg/errors"
+)
+
+// Used to store the backend implementation objects
+// Also simplifies the mocking needed for unit testing
+type instanceHandler struct {
+       // Interface that implements the Instance operations
+       client app.InstanceManager
+}
+
+func (i instanceHandler) validateBody(body interface{}) error {
+       switch b := body.(type) {
+       case app.InstanceRequest:
+               if b.CloudRegion == "" {
+                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing CloudRegion in POST request"), "CreateVnfRequest bad request")
+                       return werr
+               }
+               if b.RBName == "" || b.RBVersion == "" {
+                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing resource bundle parameters in POST request"), "CreateVnfRequest bad request")
+                       return werr
+               }
+               if b.ProfileName == "" {
+                       werr := pkgerrors.Wrap(errors.New("Invalid/Missing profile name in POST request"), "CreateVnfRequest bad request")
+                       return werr
+               }
+       }
+       return nil
+}
+
+func (i instanceHandler) createHandler(w http.ResponseWriter, r *http.Request) {
+       var resource app.InstanceRequest
+
+       err := json.NewDecoder(r.Body).Decode(&resource)
+       switch {
+       case err == io.EOF:
+               http.Error(w, "Body empty", http.StatusBadRequest)
+               return
+       case err != nil:
+               http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+               return
+       }
+
+       // Check body for expected parameters
+       err = i.validateBody(resource)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+               return
+       }
+
+       resp, err := i.client.Create(resource)
+       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(resp)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+}
+
+// getHandler retrieves information about an instance via the ID
+func (i instanceHandler) getHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       id := vars["instID"]
+
+       resp, err := i.client.Get(id)
+       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(resp)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+}
+
+// deleteHandler method terminates an instance via the ID
+func (i instanceHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       id := vars["instID"]
+
+       err := i.client.Delete(id)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+
+       w.Header().Set("Content-Type", "application/json")
+       w.WriteHeader(http.StatusAccepted)
+}
+
+// // UpdateHandler method to update a VNF instance.
+// func UpdateHandler(w http.ResponseWriter, r *http.Request) {
+//     vars := mux.Vars(r)
+//     id := vars["vnfInstanceId"]
+
+//     var resource UpdateVnfRequest
+
+//     if r.Body == nil {
+//             http.Error(w, "Body empty", http.StatusBadRequest)
+//             return
+//     }
+
+//     err := json.NewDecoder(r.Body).Decode(&resource)
+//     if err != nil {
+//             http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+//             return
+//     }
+
+//     err = validateBody(resource)
+//     if err != nil {
+//             http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+//             return
+//     }
+
+//     kubeData, err := utils.ReadCSARFromFileSystem(resource.CsarID)
+
+//     if kubeData.Deployment == nil {
+//             werr := pkgerrors.Wrap(err, "Update VNF deployment error")
+//             http.Error(w, werr.Error(), http.StatusInternalServerError)
+//             return
+//     }
+//     kubeData.Deployment.SetUID(types.UID(id))
+
+//     if err != nil {
+//             werr := pkgerrors.Wrap(err, "Update VNF deployment information error")
+//             http.Error(w, werr.Error(), http.StatusInternalServerError)
+//             return
+//     }
+
+//     // (TODO): Read kubeconfig for specific Cloud Region from local file system
+//     // if present or download it from AAI
+//     s, err := NewVNFInstanceService("../kubeconfig/config")
+//     if err != nil {
+//             http.Error(w, err.Error(), http.StatusInternalServerError)
+//             return
+//     }
+
+//     err = s.Client.UpdateDeployment(kubeData.Deployment, resource.Namespace)
+//     if err != nil {
+//             werr := pkgerrors.Wrap(err, "Update VNF error")
+
+//             http.Error(w, werr.Error(), http.StatusInternalServerError)
+//             return
+//     }
+
+//     resp := UpdateVnfResponse{
+//             DeploymentID: id,
+//     }
+
+//     w.Header().Set("Content-Type", "application/json")
+//     w.WriteHeader(http.StatusCreated)
+
+//     err = json.NewEncoder(w).Encode(resp)
+//     if err != nil {
+//             werr := pkgerrors.Wrap(err, "Parsing output of new VNF error")
+//             http.Error(w, werr.Error(), http.StatusInternalServerError)
+//     }
+// }
diff --git a/src/k8splugin/api/instancehandler_test.go b/src/k8splugin/api/instancehandler_test.go
new file mode 100644 (file)
index 0000000..d01d5df
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+Copyright 2018 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 api
+
+import (
+       "bytes"
+       "encoding/json"
+       "io"
+       "io/ioutil"
+       "net/http"
+       "net/http/httptest"
+       "reflect"
+       "testing"
+
+       "k8splugin/internal/app"
+
+       "github.com/gorilla/mux"
+       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 mockInstanceClient struct {
+       app.InstanceManager
+       // Items and err will be used to customize each test
+       // via a localized instantiation of mockInstanceClient
+       items []app.InstanceResponse
+       err   error
+}
+
+func (m *mockInstanceClient) Create(inp app.InstanceRequest) (app.InstanceResponse, error) {
+       if m.err != nil {
+               return app.InstanceResponse{}, m.err
+       }
+
+       return m.items[0], nil
+}
+
+func (m *mockInstanceClient) Get(id string) (app.InstanceResponse, error) {
+       if m.err != nil {
+               return app.InstanceResponse{}, m.err
+       }
+
+       return m.items[0], nil
+}
+
+func (m *mockInstanceClient) Delete(id string) error {
+       return m.err
+}
+
+func executeRequest(request *http.Request, router *mux.Router) *http.Response {
+       recorder := httptest.NewRecorder()
+       router.ServeHTTP(recorder, request)
+       resp := recorder.Result()
+       return resp
+}
+
+func TestInstanceCreateHandler(t *testing.T) {
+       testCases := []struct {
+               label        string
+               input        io.Reader
+               expected     app.InstanceResponse
+               expectedCode int
+               instClient   *mockInstanceClient
+       }{
+               {
+                       label:        "Missing body failure",
+                       expectedCode: http.StatusBadRequest,
+               },
+               {
+                       label:        "Invalid JSON request format",
+                       input:        bytes.NewBuffer([]byte("invalid")),
+                       expectedCode: http.StatusUnprocessableEntity,
+               },
+               {
+                       label: "Missing parameter failure",
+                       input: bytes.NewBuffer([]byte(`{
+                               "rb-name": "test-rbdef",
+                               "profile-name": "profile1",
+                               "cloud-region": "kud"
+                       }`)),
+                       expectedCode: http.StatusUnprocessableEntity,
+               },
+               {
+                       label: "Succesfully create an Instance",
+                       input: bytes.NewBuffer([]byte(`{
+                               "cloud-region": "region1",
+                               "rb-name": "test-rbdef",
+                               "rb-version": "v1",
+                               "profile-name": "profile1"
+                       }`)),
+                       expected: app.InstanceResponse{
+                               ID:          "HaKpys8e",
+                               RBName:      "test-rbdef",
+                               RBVersion:   "v1",
+                               ProfileName: "profile1",
+                               CloudRegion: "region1",
+                               Namespace:   "testnamespace",
+                               Resources: map[string][]string{
+                                       "deployment": []string{"test-deployment"},
+                                       "service":    []string{"test-service"},
+                               },
+                       },
+                       expectedCode: http.StatusCreated,
+                       instClient: &mockInstanceClient{
+                               items: []app.InstanceResponse{
+                                       {
+                                               ID:          "HaKpys8e",
+                                               RBName:      "test-rbdef",
+                                               RBVersion:   "v1",
+                                               ProfileName: "profile1",
+                                               CloudRegion: "region1",
+                                               Namespace:   "testnamespace",
+                                               Resources: map[string][]string{
+                                                       "deployment": []string{"test-deployment"},
+                                                       "service":    []string{"test-service"},
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+
+                       request := httptest.NewRequest("POST", "/v1/instance", testCase.input)
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient))
+
+                       if testCase.expectedCode != resp.StatusCode {
+                               body, _ := ioutil.ReadAll(resp.Body)
+                               t.Log(string(body))
+                               t.Fatalf("Request method returned: \n%v\n and it was expected: \n%v", resp.StatusCode, testCase.expectedCode)
+                       }
+
+                       if resp.StatusCode == http.StatusCreated {
+                               var response app.InstanceResponse
+                               err := json.NewDecoder(resp.Body).Decode(&response)
+                               if err != nil {
+                                       t.Fatalf("Parsing the returned response got an error (%s)", err)
+                               }
+                       }
+               })
+       }
+}
+
+func TestInstanceGetHandler(t *testing.T) {
+       testCases := []struct {
+               label            string
+               input            string
+               expectedCode     int
+               expectedResponse *app.InstanceResponse
+               instClient       *mockInstanceClient
+       }{
+               {
+                       label:        "Fail to retrieve Instance",
+                       input:        "HaKpys8e",
+                       expectedCode: http.StatusInternalServerError,
+                       instClient: &mockInstanceClient{
+                               err: pkgerrors.New("Internal error"),
+                       },
+               },
+               {
+                       label:        "Succesful get an Instance",
+                       input:        "HaKpys8e",
+                       expectedCode: http.StatusOK,
+                       expectedResponse: &app.InstanceResponse{
+                               ID:          "HaKpys8e",
+                               RBName:      "test-rbdef",
+                               RBVersion:   "v1",
+                               ProfileName: "profile1",
+                               CloudRegion: "region1",
+                               Namespace:   "testnamespace",
+                               Resources: map[string][]string{
+                                       "deployment": []string{"test-deployment"},
+                                       "service":    []string{"test-service"},
+                               },
+                       },
+                       instClient: &mockInstanceClient{
+                               items: []app.InstanceResponse{
+                                       {
+                                               ID:          "HaKpys8e",
+                                               RBName:      "test-rbdef",
+                                               RBVersion:   "v1",
+                                               ProfileName: "profile1",
+                                               CloudRegion: "region1",
+                                               Namespace:   "testnamespace",
+                                               Resources: map[string][]string{
+                                                       "deployment": []string{"test-deployment"},
+                                                       "service":    []string{"test-service"},
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       request := httptest.NewRequest("GET", "/v1/instance/"+testCase.input, nil)
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient))
+
+                       if testCase.expectedCode != resp.StatusCode {
+                               t.Fatalf("Request method returned: %v and it was expected: %v",
+                                       resp.StatusCode, testCase.expectedCode)
+                       }
+                       if resp.StatusCode == http.StatusOK {
+                               var response app.InstanceResponse
+                               err := json.NewDecoder(resp.Body).Decode(&response)
+                               if err != nil {
+                                       t.Fatalf("Parsing the returned response got an error (%s)", err)
+                               }
+                               if !reflect.DeepEqual(testCase.expectedResponse, &response) {
+                                       t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
+                                               &response, testCase.expectedResponse)
+                               }
+                       }
+               })
+       }
+}
+
+func TestDeleteHandler(t *testing.T) {
+       testCases := []struct {
+               label        string
+               input        string
+               expectedCode int
+               instClient   *mockInstanceClient
+       }{
+               {
+                       label:        "Fail to destroy VNF",
+                       input:        "HaKpys8e",
+                       expectedCode: http.StatusInternalServerError,
+                       instClient: &mockInstanceClient{
+                               err: pkgerrors.New("Internal error"),
+                       },
+               },
+               {
+                       label:        "Succesful delete a VNF",
+                       input:        "HaKpys8e",
+                       expectedCode: http.StatusAccepted,
+                       instClient:   &mockInstanceClient{},
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       request := httptest.NewRequest("DELETE", "/v1/instance/"+testCase.input, nil)
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient))
+
+                       if testCase.expectedCode != resp.StatusCode {
+                               t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode)
+                       }
+               })
+       }
+}
+
+// TODO: Update this test when the UpdateVNF endpoint is fixed.
+/*
+func TestVNFInstanceUpdate(t *testing.T) {
+       t.Run("Succesful update a VNF", func(t *testing.T) {
+               payload := []byte(`{
+                       "cloud_region_id": "region1",
+                       "csar_id": "UUID-1",
+                       "oof_parameters": [{
+                               "key1": "value1",
+                               "key2": "value2",
+                               "key3": {}
+                       }],
+                       "network_parameters": {
+                               "oam_ip_address": {
+                                       "connection_point": "string",
+                                       "ip_address": "string",
+                                       "workload_name": "string"
+                               }
+                       }
+               }`)
+               expected := &UpdateVnfResponse{
+                       DeploymentID: "1",
+               }
+
+               var result UpdateVnfResponse
+
+               req := httptest.NewRequest("PUT", "/v1/vnf_instances/1", bytes.NewBuffer(payload))
+
+               GetVNFClient = func(configPath string) (krd.VNFInstanceClientInterface, error) {
+                       return &mockClient{
+                               update: func() error {
+                                       return nil
+                               },
+                       }, nil
+               }
+               utils.ReadCSARFromFileSystem = func(csarID string) (*krd.KubernetesData, error) {
+                       kubeData := &krd.KubernetesData{
+                               Deployment: &appsV1.Deployment{},
+                               Service:    &coreV1.Service{},
+                       }
+                       return kubeData, nil
+               }
+
+               response := executeRequest(req)
+               checkResponseCode(t, http.StatusCreated, response.Code)
+
+               err := json.NewDecoder(response.Body).Decode(&result)
+               if err != nil {
+                       t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", err, expected.DeploymentID)
+               }
+
+               if resp.DeploymentID != expected.DeploymentID {
+                       t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", resp.DeploymentID, expected.DeploymentID)
+               }
+       })
+}
+*/
index e0e715b..e600c0d 100644 (file)
@@ -15,35 +15,29 @@ package main
 
 import (
        "context"
-       "flag"
        "log"
+       "math/rand"
        "net/http"
        "os"
        "os/signal"
-       "path/filepath"
-
-       "github.com/gorilla/handlers"
-       "k8s.io/client-go/util/homedir"
+       "time"
 
        "k8splugin/api"
        utils "k8splugin/internal"
+
+       "github.com/gorilla/handlers"
 )
 
 func main() {
-       var kubeconfig string
-
-       home := homedir.HomeDir()
-       if home != "" {
-               kubeconfig = *flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
-       }
-       flag.Parse()
 
        err := utils.CheckInitialSettings()
        if err != nil {
                log.Fatal(err)
        }
 
-       httpRouter := api.NewRouter(kubeconfig, nil, nil)
+       rand.Seed(time.Now().UnixNano())
+
+       httpRouter := api.NewRouter(nil, nil, nil)
        loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter)
        log.Println("Starting Kubernetes Multicloud API")
 
index 3555afd..fa5fdfd 100644 (file)
@@ -14,31 +14,187 @@ limitations under the License.
 package app
 
 import (
-       "errors"
+       "log"
+       "os"
+       "strings"
 
-       pkgerrors "github.com/pkg/errors"
+       utils "k8splugin/internal"
 
+       pkgerrors "github.com/pkg/errors"
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/tools/clientcmd"
+       "k8s.io/helm/pkg/tiller"
 )
 
-// GetKubeClient loads the Kubernetes configuation values stored into the local configuration file
-var GetKubeClient = func(configPath string) (kubernetes.Clientset, error) {
-       var clientset *kubernetes.Clientset
+type kubernetesClient struct {
+       clientSet *kubernetes.Clientset
+}
 
+// GetKubeClient loads the Kubernetes configuation values stored into the local configuration file
+func (k *kubernetesClient) init(configPath string) error {
        if configPath == "" {
-               return *clientset, errors.New("config not passed and is not found in ~/.kube. ")
+               return pkgerrors.New("config not passed and is not found in ~/.kube. ")
        }
 
        config, err := clientcmd.BuildConfigFromFlags("", configPath)
        if err != nil {
-               return kubernetes.Clientset{}, pkgerrors.Wrap(err, "setConfig: Build config from flags raised an error")
+               return pkgerrors.Wrap(err, "setConfig: Build config from flags raised an error")
+       }
+
+       k.clientSet, err = kubernetes.NewForConfig(config)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (k *kubernetesClient) ensureNamespace(namespace string) error {
+       namespacePlugin, ok := utils.LoadedPlugins["namespace"]
+       if !ok {
+               return pkgerrors.New("No plugin for namespace resource found")
+       }
+
+       symGetNamespaceFunc, err := namespacePlugin.Lookup("Get")
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error fetching get namespace function")
+       }
+
+       ns, _ := symGetNamespaceFunc.(func(string, string, kubernetes.Interface) (string, error))(
+               namespace, namespace, k.clientSet)
+
+       if ns == "" {
+               log.Println("Creating " + namespace + " namespace")
+               symGetNamespaceFunc, err := namespacePlugin.Lookup("Create")
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Error fetching create namespace plugin")
+               }
+               namespaceResource := &utils.ResourceData{
+                       Namespace: namespace,
+               }
+
+               _, err = symGetNamespaceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
+                       namespaceResource, k.clientSet)
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Error creating "+namespace+" namespace")
+               }
+       }
+       return nil
+}
+
+func (k *kubernetesClient) createKind(kind string, files []string, namespace string) ([]string, error) {
+
+       log.Println("Processing items of Kind: " + kind)
+
+       //Iterate over each file of a particular kind here
+       var resourcesCreated []string
+       for _, f := range files {
+               if _, err := os.Stat(f); os.IsNotExist(err) {
+                       return nil, pkgerrors.New("File " + f + "does not exists")
+               }
+
+               log.Println("Processing file: " + f)
+
+               //Populate the namespace from profile instead of instance body
+               genericKubeData := &utils.ResourceData{
+                       YamlFilePath: f,
+                       Namespace:    namespace,
+               }
+
+               typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
+               if !ok {
+                       return nil, pkgerrors.New("No plugin for kind " + kind + " found")
+               }
+
+               symCreateResourceFunc, err := typePlugin.Lookup("Create")
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Error fetching "+kind+" plugin")
+               }
+
+               createdResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
+                       genericKubeData, k.clientSet)
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Error in plugin "+kind+" plugin")
+               }
+               log.Print(createdResourceName + " created")
+               resourcesCreated = append(resourcesCreated, createdResourceName)
+       }
+
+       return resourcesCreated, nil
+}
+
+func (k *kubernetesClient) createResources(resMap map[string][]string,
+       namespace string) (map[string][]string, error) {
+
+       err := k.ensureNamespace(namespace)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Creating Namespace")
+       }
+
+       createdResourceMap := make(map[string][]string)
+       // Create all the known kinds in the InstallOrder
+       for _, kind := range tiller.InstallOrder {
+               files, ok := resMap[kind]
+               if !ok {
+                       log.Println("Kind " + kind + " not found. Skipping...")
+                       continue
+               }
+
+               resourcesCreated, err := k.createKind(kind, files, namespace)
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Error creating kind: "+kind)
+               }
+
+               createdResourceMap[kind] = resourcesCreated
+               delete(resMap, kind)
        }
 
-       clientset, err = kubernetes.NewForConfig(config)
+       //Create the remaining kinds from the resMap
+       for kind, files := range resMap {
+               resourcesCreated, err := k.createKind(kind, files, namespace)
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Error creating kind: "+kind)
+               }
+
+               createdResourceMap[kind] = resourcesCreated
+               delete(resMap, kind)
+       }
+
+       return createdResourceMap, nil
+}
+
+func (k *kubernetesClient) deleteKind(kind string, resources []string, namespace string) error {
+       log.Println("Deleting items of Kind: " + kind)
+
+       typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
+       if !ok {
+               return pkgerrors.New("No plugin for resource " + kind + " found")
+       }
+
+       symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
        if err != nil {
-               return *clientset, err
+               return pkgerrors.Wrap(err, "Error fetching "+kind+" plugin")
+       }
+
+       for _, res := range resources {
+               log.Println("Deleting resource: " + res)
+               err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
+                       res, namespace, k.clientSet)
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Error destroying "+res)
+               }
+       }
+       return nil
+}
+
+func (k *kubernetesClient) deleteResources(resMap map[string][]string, namespace string) error {
+       //TODO: Investigate if deletion should be in a particular order
+       for kind, resourceNames := range resMap {
+               err := k.deleteKind(kind, resourceNames, namespace)
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Deleting resources")
+               }
        }
 
-       return *clientset, nil
+       return nil
 }
index 7189272..5999cfa 100644 (file)
@@ -14,21 +14,105 @@ limitations under the License.
 package app
 
 import (
+       "os"
+       "plugin"
        "reflect"
        "testing"
+
+       utils "k8splugin/internal"
+
+       pkgerrors "github.com/pkg/errors"
+       "k8s.io/client-go/kubernetes"
 )
 
-func TestGetKubeClient(t *testing.T) {
+func LoadMockPlugins(krdLoadedPlugins map[string]*plugin.Plugin) error {
+       if _, err := os.Stat("../../mock_files/mock_plugins/mockplugin.so"); os.IsNotExist(err) {
+               return pkgerrors.New("mockplugin.so does not exist. Please compile mockplugin.go to generate")
+       }
+
+       mockPlugin, err := plugin.Open("../../mock_files/mock_plugins/mockplugin.so")
+       if err != nil {
+               return pkgerrors.Wrap(err, "Opening mock plugins")
+       }
+
+       krdLoadedPlugins["namespace"] = mockPlugin
+       krdLoadedPlugins["deployment"] = mockPlugin
+       krdLoadedPlugins["service"] = mockPlugin
+
+       return nil
+}
+
+func TestInit(t *testing.T) {
        t.Run("Successfully create Kube Client", func(t *testing.T) {
 
-               clientset, err := GetKubeClient("../../mock_files/mock_configs/mock_config")
+               kubeClient := kubernetesClient{}
+               err := kubeClient.init("../../mock_files/mock_configs/mock_config")
                if err != nil {
                        t.Fatalf("TestGetKubeClient returned an error (%s)", err)
                }
 
-               if reflect.TypeOf(clientset).Name() != "Clientset" {
-                       t.Fatalf("TestGetKubeClient returned :\n result=%v\n expected=%v", clientset, "Clientset")
+               name := reflect.TypeOf(kubeClient.clientSet).Elem().Name()
+               if name != "Clientset" {
+                       t.Fatalf("TestGetKubeClient returned :\n result=%v\n expected=%v", name, "Clientset")
                }
 
        })
 }
+
+func TestCreateResources(t *testing.T) {
+       oldkrdPluginData := utils.LoadedPlugins
+
+       defer func() {
+               utils.LoadedPlugins = oldkrdPluginData
+       }()
+
+       err := LoadMockPlugins(utils.LoadedPlugins)
+       if err != nil {
+               t.Fatalf("LoadMockPlugins returned an error (%s)", err)
+       }
+
+       k8 := kubernetesClient{
+               clientSet: &kubernetes.Clientset{},
+       }
+
+       t.Run("Successfully delete resources", func(t *testing.T) {
+               data := map[string][]string{
+                       "Deployment": []string{"../../mock_files/mock_yamls/deployment.yaml"},
+                       "Service":    []string{"../../mock_files/mock_yamls/service.yaml"},
+               }
+
+               _, err := k8.createResources(data, "testnamespace")
+               if err != nil {
+                       t.Fatalf("TestCreateResources returned an error (%s)", err)
+               }
+       })
+}
+
+func TestDeleteResources(t *testing.T) {
+       oldkrdPluginData := utils.LoadedPlugins
+
+       defer func() {
+               utils.LoadedPlugins = oldkrdPluginData
+       }()
+
+       err := LoadMockPlugins(utils.LoadedPlugins)
+       if err != nil {
+               t.Fatalf("LoadMockPlugins returned an error (%s)", err)
+       }
+
+       k8 := kubernetesClient{
+               clientSet: &kubernetes.Clientset{},
+       }
+
+       t.Run("Successfully delete resources", func(t *testing.T) {
+               data := map[string][]string{
+                       "Deployment": []string{"deployment-1", "deployment-2"},
+                       "Service":    []string{"service-1", "service-2"},
+               }
+
+               err := k8.deleteResources(data, "test")
+               if err != nil {
+                       t.Fatalf("TestCreateVNF returned an error (%s)", err)
+               }
+       })
+}
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
new file mode 100644 (file)
index 0000000..a5b35fe
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2018 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 app
+
+import (
+       "encoding/base64"
+       "encoding/json"
+       "math/rand"
+       "os"
+
+       "k8splugin/internal/db"
+       "k8splugin/internal/rb"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+// InstanceRequest contains the parameters needed for instantiation
+// of profiles
+type InstanceRequest struct {
+       RBName      string            `json:"rb-name"`
+       RBVersion   string            `json:"rb-version"`
+       ProfileName string            `json:"profile-name"`
+       CloudRegion string            `json:"cloud-region"`
+       Labels      map[string]string `json:"labels"`
+}
+
+// InstanceResponse contains the response from instantiation
+type InstanceResponse struct {
+       ID          string              `json:"id"`
+       RBName      string              `json:"rb-name"`
+       RBVersion   string              `json:"rb-version"`
+       ProfileName string              `json:"profile-name"`
+       CloudRegion string              `json:"cloud-region"`
+       Namespace   string              `json:"namespace"`
+       Resources   map[string][]string `json:"resources"`
+}
+
+// InstanceManager is an interface exposes the instantiation functionality
+type InstanceManager interface {
+       Create(i InstanceRequest) (InstanceResponse, error)
+       Get(id string) (InstanceResponse, error)
+       Delete(id string) error
+}
+
+// InstanceKey is used as the primary key in the db
+type InstanceKey struct {
+       ID string `json:"id"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (dk InstanceKey) String() string {
+       out, err := json.Marshal(dk)
+       if err != nil {
+               return ""
+       }
+
+       return string(out)
+}
+
+// InstanceClient implements the InstanceManager interface
+// It will also be used to maintain some localized state
+type InstanceClient struct {
+       storeName string
+       tagInst   string
+}
+
+// Using 6 bytes of randomness to generate an 8 character string
+func generateInstanceID() string {
+       b := make([]byte, 6)
+       rand.Read(b)
+       return base64.URLEncoding.EncodeToString(b)
+}
+
+// NewInstanceClient returns an instance of the InstanceClient
+// which implements the InstanceManager
+func NewInstanceClient() *InstanceClient {
+       return &InstanceClient{
+               storeName: "rbdef",
+               tagInst:   "instance",
+       }
+}
+
+// Create an entry for the resource bundle profile in the database
+func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
+
+       // Name is required
+       if i.RBName == "" || i.RBVersion == "" || i.ProfileName == "" || i.CloudRegion == "" {
+               return InstanceResponse{},
+                       pkgerrors.New("RBName, RBversion, ProfileName, CloudRegion are required to create a new instance")
+       }
+
+       //Check if profile exists
+       profile, err := rb.NewProfileClient().Get(i.RBName, i.RBVersion, i.ProfileName)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.New("Unable to find Profile to create instance")
+       }
+
+       overrideValues := []string{}
+
+       //Execute the kubernetes create command
+       resMap, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
+       }
+
+       k8sClient := kubernetesClient{}
+       err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + i.CloudRegion)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information")
+       }
+
+       createdResources, err := k8sClient.createResources(resMap, profile.Namespace)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Create Kubernetes Resources")
+       }
+
+       id := generateInstanceID()
+
+       //Compose the return response
+       resp := InstanceResponse{
+               ID:          id,
+               RBName:      i.RBName,
+               RBVersion:   i.RBVersion,
+               ProfileName: i.ProfileName,
+               CloudRegion: i.CloudRegion,
+               Namespace:   profile.Namespace,
+               Resources:   createdResources,
+       }
+
+       key := InstanceKey{
+               ID: id,
+       }
+       err = db.DBconn.Create(v.storeName, key, v.tagInst, resp)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Creating Instance DB Entry")
+       }
+
+       return resp, nil
+}
+
+// Get returns the instance for corresponding ID
+func (v *InstanceClient) Get(id string) (InstanceResponse, error) {
+       key := InstanceKey{
+               ID: id,
+       }
+       value, err := db.DBconn.Read(v.storeName, key, v.tagInst)
+       if err != nil {
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Get Instance")
+       }
+
+       //value is a byte array
+       if value != nil {
+               resp := InstanceResponse{}
+               err = db.DBconn.Unmarshal(value, &resp)
+               if err != nil {
+                       return InstanceResponse{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value")
+               }
+               return resp, nil
+       }
+
+       return InstanceResponse{}, pkgerrors.New("Error getting Instance")
+}
+
+// Delete the Instance from database
+func (v *InstanceClient) Delete(id string) error {
+       inst, err := v.Get(id)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error getting Instance")
+       }
+
+       k8sClient := kubernetesClient{}
+       err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + inst.CloudRegion)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Getting CloudRegion Information")
+       }
+
+       err = k8sClient.deleteResources(inst.Resources, inst.Namespace)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Deleting Instance Resources")
+       }
+
+       key := InstanceKey{
+               ID: id,
+       }
+       err = db.DBconn.Delete(v.storeName, key, v.tagInst)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Delete Instance")
+       }
+
+       return nil
+}
similarity index 65%
rename from src/k8splugin/internal/app/vnfhelper_test.go
rename to src/k8splugin/internal/app/instance_test.go
index 7587e5d..480569c 100644 (file)
@@ -14,73 +14,27 @@ limitations under the License.
 package app
 
 import (
-       "io/ioutil"
        "log"
        "os"
-       "plugin"
+       "reflect"
        "testing"
 
-       pkgerrors "github.com/pkg/errors"
-       yaml "gopkg.in/yaml.v2"
-       "k8s.io/client-go/kubernetes"
-
        utils "k8splugin/internal"
        "k8splugin/internal/db"
        "k8splugin/internal/rb"
 )
 
-func LoadMockPlugins(krdLoadedPlugins *map[string]*plugin.Plugin) error {
-       if _, err := os.Stat("../../mock_files/mock_plugins/mockplugin.so"); os.IsNotExist(err) {
-               return pkgerrors.New("mockplugin.so does not exist. Please compile mockplugin.go to generate")
-       }
-
-       mockPlugin, err := plugin.Open("../../mock_files/mock_plugins/mockplugin.so")
-       if err != nil {
-               return pkgerrors.Cause(err)
-       }
-
-       (*krdLoadedPlugins)["namespace"] = mockPlugin
-       (*krdLoadedPlugins)["deployment"] = mockPlugin
-       (*krdLoadedPlugins)["service"] = mockPlugin
-
-       return nil
-}
-
-func TestCreateVNF(t *testing.T) {
+func TestInstanceCreate(t *testing.T) {
        oldkrdPluginData := utils.LoadedPlugins
-       oldReadMetadataFile := ReadMetadataFile
-
        defer func() {
                utils.LoadedPlugins = oldkrdPluginData
-               ReadMetadataFile = oldReadMetadataFile
        }()
-
-       err := LoadMockPlugins(&utils.LoadedPlugins)
+       err := LoadMockPlugins(utils.LoadedPlugins)
        if err != nil {
-               t.Fatalf("TestCreateVNF returned an error (%s)", err)
+               t.Fatalf("LoadMockPlugins returned an error (%s)", err)
        }
 
-       ReadMetadataFile = func(yamlFilePath string) (MetadataFile, error) {
-               var seqFile MetadataFile
-
-               if _, err := os.Stat(yamlFilePath); err == nil {
-                       rawBytes, err := ioutil.ReadFile("../../mock_files/mock_yamls/metadata.yaml")
-                       if err != nil {
-                               return seqFile, pkgerrors.Wrap(err, "Metadata YAML file read error")
-                       }
-
-                       err = yaml.Unmarshal(rawBytes, &seqFile)
-                       if err != nil {
-                               return seqFile, pkgerrors.Wrap(err, "Metadata YAML file unmarshall error")
-                       }
-               }
-
-               return seqFile, nil
-       }
-
-       kubeclient := kubernetes.Clientset{}
-
-       t.Run("Successfully create VNF", func(t *testing.T) {
+       t.Run("Successfully create Instance", func(t *testing.T) {
                db.DBconn = &db.MockDB{
                        Items: map[string]map[string][]byte{
                                rb.ProfileKey{RBName: "test-rbdef", RBVersion: "v1",
@@ -190,60 +144,180 @@ func TestCreateVNF(t *testing.T) {
                                },
                        },
                }
-               externaluuid, data, err := CreateVNF("uuid", "cloudregion1",
-                       rb.Profile{
-                               RBName:            "test-rbdef",
-                               RBVersion:         "v1",
-                               ProfileName:       "profile1",
-                               ReleaseName:       "testprofilereleasename",
-                               Namespace:         "testnamespace",
-                               KubernetesVersion: "1.12.3",
-                       }, &kubeclient)
+
+               ic := NewInstanceClient()
+               input := InstanceRequest{
+                       RBName:      "test-rbdef",
+                       RBVersion:   "v1",
+                       ProfileName: "profile1",
+                       CloudRegion: "mock_config",
+               }
+
+               err := os.Setenv("KUBE_CONFIG_DIR", "../../mock_files/mock_configs")
                if err != nil {
-                       t.Fatalf("TestCreateVNF returned an error (%s)", err)
+                       t.Fatalf("TestInstanceCreate returned an error (%s)", err)
                }
 
-               log.Println(externaluuid)
+               ir, err := ic.Create(input)
+               if err != nil {
+                       t.Fatalf("TestInstanceCreate returned an error (%s)", err)
+               }
+
+               log.Println(ir)
 
-               if data == nil {
-                       t.Fatalf("TestCreateVNF returned empty data (%s)", data)
+               if len(ir.Resources) == 0 {
+                       t.Fatalf("TestInstanceCreate returned empty data (%s)", ir)
                }
        })
 
 }
 
-func TestDeleteVNF(t *testing.T) {
+func TestInstanceGet(t *testing.T) {
        oldkrdPluginData := utils.LoadedPlugins
 
        defer func() {
                utils.LoadedPlugins = oldkrdPluginData
        }()
 
-       err := LoadMockPlugins(&utils.LoadedPlugins)
+       err := LoadMockPlugins(utils.LoadedPlugins)
        if err != nil {
-               t.Fatalf("TestCreateVNF returned an error (%s)", err)
+               t.Fatalf("LoadMockPlugins returned an error (%s)", err)
        }
 
-       kubeclient := kubernetes.Clientset{}
-
-       t.Run("Successfully delete VNF", func(t *testing.T) {
-               data := map[string][]string{
-                       "deployment": []string{"cloud1-default-uuid-sisedeploy"},
-                       "service":    []string{"cloud1-default-uuid-sisesvc"},
+       t.Run("Successfully Get Instance", func(t *testing.T) {
+               db.DBconn = &db.MockDB{
+                       Items: map[string]map[string][]byte{
+                               InstanceKey{ID: "HaKpys8e"}.String(): {
+                                       "instance": []byte(
+                                               "{\"profile-name\":\"profile1\"," +
+                                                       "\"id\":\"HaKpys8e\"," +
+                                                       "\"namespace\":\"testnamespace\"," +
+                                                       "\"rb-name\":\"test-rbdef\"," +
+                                                       "\"rb-version\":\"v1\"," +
+                                                       "\"cloud-region\":\"region1\"," +
+                                                       "\"resources\": {" +
+                                                       "\"deployment\": [\"test-deployment\"]," +
+                                                       "\"service\": [\"test-service\"]" +
+                                                       "}}"),
+                               },
+                       },
                }
 
-               err := DestroyVNF(data, "test", &kubeclient)
+               expected := InstanceResponse{
+                       ID:          "HaKpys8e",
+                       RBName:      "test-rbdef",
+                       RBVersion:   "v1",
+                       ProfileName: "profile1",
+                       CloudRegion: "region1",
+                       Namespace:   "testnamespace",
+                       Resources: map[string][]string{
+                               "deployment": []string{"test-deployment"},
+                               "service":    []string{"test-service"},
+                       },
+               }
+               ic := NewInstanceClient()
+               id := "HaKpys8e"
+               data, err := ic.Get(id)
                if err != nil {
-                       t.Fatalf("TestCreateVNF returned an error (%s)", err)
+                       t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+               }
+               if !reflect.DeepEqual(expected, data) {
+                       t.Fatalf("TestInstanceGet returned:\n result=%v\n expected=%v",
+                               data, expected)
+               }
+       })
+
+       t.Run("Get non-existing Instance", func(t *testing.T) {
+               db.DBconn = &db.MockDB{
+                       Items: map[string]map[string][]byte{
+                               InstanceKey{ID: "HaKpys8e"}.String(): {
+                                       "instance": []byte(
+                                               "{\"profile-name\":\"profile1\"," +
+                                                       "\"id\":\"HaKpys8e\"," +
+                                                       "\"namespace\":\"testnamespace\"," +
+                                                       "\"rb-name\":\"test-rbdef\"," +
+                                                       "\"rb-version\":\"v1\"," +
+                                                       "\"cloud-region\":\"mock_config\"," +
+                                                       "\"resources\": {" +
+                                                       "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+                                                       "\"service\": [\"service-1\",\"service-2\"]" +
+                                                       "}}"),
+                               },
+                       },
+               }
+
+               ic := NewInstanceClient()
+               id := "non-existing"
+               _, err := ic.Get(id)
+               if err == nil {
+                       t.Fatal("Expected error, got pass", err)
                }
        })
 }
 
-func TestReadMetadataFile(t *testing.T) {
-       t.Run("Successfully read Metadata YAML file", func(t *testing.T) {
-               _, err := ReadMetadataFile("../../mock_files//mock_yamls/metadata.yaml")
+func TestInstanceDelete(t *testing.T) {
+       oldkrdPluginData := utils.LoadedPlugins
+
+       defer func() {
+               utils.LoadedPlugins = oldkrdPluginData
+       }()
+
+       err := LoadMockPlugins(utils.LoadedPlugins)
+       if err != nil {
+               t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+       }
+
+       t.Run("Successfully delete Instance", func(t *testing.T) {
+               db.DBconn = &db.MockDB{
+                       Items: map[string]map[string][]byte{
+                               InstanceKey{ID: "HaKpys8e"}.String(): {
+                                       "instance": []byte(
+                                               "{\"profile-name\":\"profile1\"," +
+                                                       "\"id\":\"HaKpys8e\"," +
+                                                       "\"namespace\":\"testnamespace\"," +
+                                                       "\"rb-name\":\"test-rbdef\"," +
+                                                       "\"rb-version\":\"v1\"," +
+                                                       "\"cloud-region\":\"mock_config\"," +
+                                                       "\"resources\": {" +
+                                                       "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+                                                       "\"service\": [\"service-1\",\"service-2\"]" +
+                                                       "}}"),
+                               },
+                       },
+               }
+
+               ic := NewInstanceClient()
+               id := "HaKpys8e"
+               err := ic.Delete(id)
                if err != nil {
-                       t.Fatalf("TestReadMetadataFile returned an error (%s)", err)
+                       t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+               }
+       })
+
+       t.Run("Delete non-existing Instance", func(t *testing.T) {
+               db.DBconn = &db.MockDB{
+                       Items: map[string]map[string][]byte{
+                               InstanceKey{ID: "HaKpys8e"}.String(): {
+                                       "instance": []byte(
+                                               "{\"profile-name\":\"profile1\"," +
+                                                       "\"id\":\"HaKpys8e\"," +
+                                                       "\"namespace\":\"testnamespace\"," +
+                                                       "\"rb-name\":\"test-rbdef\"," +
+                                                       "\"rb-version\":\"v1\"," +
+                                                       "\"cloud-region\":\"mock_config\"," +
+                                                       "\"resources\": {" +
+                                                       "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+                                                       "\"service\": [\"service-1\",\"service-2\"]" +
+                                                       "}}"),
+                               },
+                       },
+               }
+
+               ic := NewInstanceClient()
+               id := "non-existing"
+               err := ic.Delete(id)
+               if err == nil {
+                       t.Fatal("Expected error, got pass", err)
                }
        })
 }
diff --git a/src/k8splugin/internal/app/vnfhelper.go b/src/k8splugin/internal/app/vnfhelper.go
deleted file mode 100644 (file)
index c5783d6..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-Copyright 2018 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 app
-
-import (
-       "encoding/hex"
-       "io/ioutil"
-       "log"
-       "math/rand"
-       "os"
-       "strings"
-
-       "k8s.io/client-go/kubernetes"
-
-       pkgerrors "github.com/pkg/errors"
-       yaml "gopkg.in/yaml.v2"
-
-       utils "k8splugin/internal"
-       "k8splugin/internal/rb"
-)
-
-func generateExternalVNFID() string {
-       b := make([]byte, 2)
-       rand.Read(b)
-       return hex.EncodeToString(b)
-}
-
-func ensuresNamespace(namespace string, kubeclient kubernetes.Interface) error {
-       namespacePlugin, ok := utils.LoadedPlugins["namespace"]
-       if !ok {
-               return pkgerrors.New("No plugin for namespace resource found")
-       }
-
-       symGetNamespaceFunc, err := namespacePlugin.Lookup("Get")
-       if err != nil {
-               return pkgerrors.Wrap(err, "Error fetching get namespace function")
-       }
-
-       ns, _ := symGetNamespaceFunc.(func(string, string, kubernetes.Interface) (string, error))(
-               namespace, namespace, kubeclient)
-
-       if ns == "" {
-               log.Println("Creating " + namespace + " namespace")
-               symGetNamespaceFunc, err := namespacePlugin.Lookup("Create")
-               if err != nil {
-                       return pkgerrors.Wrap(err, "Error fetching create namespace plugin")
-               }
-               namespaceResource := &utils.ResourceData{
-                       Namespace: namespace,
-               }
-
-               _, err = symGetNamespaceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
-                       namespaceResource, kubeclient)
-               if err != nil {
-                       return pkgerrors.Wrap(err, "Error creating "+namespace+" namespace")
-               }
-       }
-       return nil
-}
-
-// CreateVNF reads the CSAR files from the files system and creates them one by one
-var CreateVNF = func(csarID string, cloudRegionID string, profile rb.Profile, kubeclient *kubernetes.Clientset) (string, map[string][]string, error) {
-
-       overrideValues := []string{}
-       //Make sure that the namespace exists before trying to create any resources
-       if err := ensuresNamespace(profile.Namespace, kubeclient); err != nil {
-               return "", nil, pkgerrors.Wrap(err, "Error while ensuring namespace: "+profile.Namespace)
-       }
-       externalVNFID := generateExternalVNFID()
-       internalVNFID := cloudRegionID + "-" + profile.Namespace + "-" + externalVNFID
-
-       metaMap, err := rb.NewProfileClient().Resolve(profile.RBName, profile.RBVersion, profile.ProfileName, overrideValues)
-       if err != nil {
-               return "", nil, pkgerrors.Wrap(err, "Error resolving helm charts")
-       }
-
-       resourceYAMLNameMap := make(map[string][]string)
-       // Iterates over the resources defined in the metadata map to create kubernetes resources
-       log.Printf("%d resource(s) type(s) to be processed", len(metaMap))
-       for res, filePaths := range metaMap {
-               //Convert resource to lower case as the map index is lowercase
-               resource := strings.ToLower(res)
-               log.Println("Processing items of " + string(resource) + " resource")
-               var resourcesCreated []string
-               for _, filepath := range filePaths {
-
-                       if _, err := os.Stat(filepath); os.IsNotExist(err) {
-                               return "", nil, pkgerrors.New("File " + filepath + "does not exists")
-                       }
-                       log.Println("Processing file: " + filepath)
-
-                       //Populate the namespace from profile instead of instance body
-                       genericKubeData := &utils.ResourceData{
-                               YamlFilePath: filepath,
-                               Namespace:    profile.Namespace,
-                               VnfId:        internalVNFID,
-                       }
-
-                       typePlugin, ok := utils.LoadedPlugins[resource]
-                       if !ok {
-                               return "", nil, pkgerrors.New("No plugin for resource " + resource + " found")
-                       }
-
-                       symCreateResourceFunc, err := typePlugin.Lookup("Create")
-                       if err != nil {
-                               return "", nil, pkgerrors.Wrap(err, "Error fetching "+resource+" plugin")
-                       }
-
-                       internalResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
-                               genericKubeData, kubeclient)
-                       if err != nil {
-                               return "", nil, pkgerrors.Wrap(err, "Error in plugin "+resource+" plugin")
-                       }
-                       log.Print(internalResourceName + " succesful resource created")
-                       resourcesCreated = append(resourcesCreated, internalResourceName)
-               }
-               resourceYAMLNameMap[resource] = resourcesCreated
-       }
-
-       return externalVNFID, resourceYAMLNameMap, nil
-}
-
-// DestroyVNF deletes VNFs based on data passed
-var DestroyVNF = func(data map[string][]string, namespace string, kubeclient *kubernetes.Clientset) error {
-       /* data:
-       {
-               "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
-               "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
-       },
-       */
-
-       for resourceName, resourceList := range data {
-               typePlugin, ok := utils.LoadedPlugins[resourceName]
-               if !ok {
-                       return pkgerrors.New("No plugin for resource " + resourceName + " found")
-               }
-
-               symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
-               if err != nil {
-                       return pkgerrors.Wrap(err, "Error fetching "+resourceName+" plugin")
-               }
-
-               for _, resourceName := range resourceList {
-
-                       log.Println("Deleting resource: " + resourceName)
-
-                       err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
-                               resourceName, namespace, kubeclient)
-                       if err != nil {
-                               return pkgerrors.Wrap(err, "Error destroying "+resourceName)
-                       }
-               }
-       }
-
-       return nil
-}
-
-// MetadataFile stores the metadata of execution
-type MetadataFile struct {
-       ResourceTypePathMap map[string][]string `yaml:"resources"`
-}
-
-// ReadMetadataFile reads the metadata yaml to return the order or reads
-var ReadMetadataFile = func(path string) (MetadataFile, error) {
-       var metadataFile MetadataFile
-
-       if _, err := os.Stat(path); os.IsNotExist(err) {
-               return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file does not exist")
-       }
-
-       log.Println("Reading metadata YAML: " + path)
-       yamlFile, err := ioutil.ReadFile(path)
-       if err != nil {
-               return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file read error")
-       }
-
-       err = yaml.Unmarshal(yamlFile, &metadataFile)
-       if err != nil {
-               return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file unmarshal error")
-       }
-       log.Printf("metadata:\n%v", metadataFile)
-
-       return metadataFile, nil
-}
index 80a9d59..bdc2130 100644 (file)
@@ -23,12 +23,12 @@ func main() {}
 
 // Create object in a specific Kubernetes resource
 func Create(data *utils.ResourceData, client kubernetes.Interface) (string, error) {
-       return "externalUUID", nil
+       return "resource-name", nil
 }
 
 // List of existing resources
 func List(namespace string, client kubernetes.Interface) ([]string, error) {
-       returnVal := []string{"cloud1-default-uuid1", "cloud1-default-uuid2"}
+       returnVal := []string{"resource-name-1", "resource-name-2"}
        return returnVal, nil
 }
 
index b500c86..7ac3175 100644 (file)
@@ -41,8 +41,6 @@ func Create(data *utils.ResourceData, client kubernetes.Interface) (string, erro
                return "", pkgerrors.New("Decoded object contains another resource different than Deployment")
        }
        deployment.Namespace = namespace
-       deployment.Name = data.VnfId + "-" + deployment.Name
-
        result, err := client.AppsV1().Deployments(namespace).Create(deployment)
        if err != nil {
                return "", pkgerrors.Wrap(err, "Create Deployment error")
index 55e0c80..446f332 100644 (file)
@@ -28,7 +28,6 @@ import (
 func TestCreateDeployment(t *testing.T) {
        namespace := "test1"
        name := "mock-deployment"
-       internalVNFID := "1"
        testCases := []struct {
                label          string
                input          *utils.ResourceData
@@ -47,7 +46,6 @@ func TestCreateDeployment(t *testing.T) {
                {
                        label: "Successfully create a deployment",
                        input: &utils.ResourceData{
-                               VnfId:        internalVNFID,
                                YamlFilePath: "../../mock_files/mock_yamls/deployment.yaml",
                        },
                        clientOutput: &appsV1.Deployment{
@@ -56,7 +54,7 @@ func TestCreateDeployment(t *testing.T) {
                                        Namespace: namespace,
                                },
                        },
-                       expectedResult: internalVNFID + "-" + name,
+                       expectedResult: name,
                },
        }
 
index e9b45fc..ea5aeca 100644 (file)
@@ -42,7 +42,6 @@ func Create(data *utils.ResourceData, client kubernetes.Interface) (string, erro
                return "", pkgerrors.New("Decoded object contains another resource different than Service")
        }
        service.Namespace = namespace
-       service.Name = data.VnfId + "-" + service.Name
 
        result, err := client.CoreV1().Services(namespace).Create(service)
        if err != nil {
index 7353f24..d361486 100644 (file)
@@ -28,7 +28,6 @@ import (
 func TestCreateService(t *testing.T) {
        namespace := "test1"
        name := "mock-service"
-       internalVNFID := "1"
        testCases := []struct {
                label          string
                input          *utils.ResourceData
@@ -47,7 +46,6 @@ func TestCreateService(t *testing.T) {
                {
                        label: "Successfully create a service",
                        input: &utils.ResourceData{
-                               VnfId:        internalVNFID,
                                YamlFilePath: "../../mock_files/mock_yamls/service.yaml",
                        },
                        clientOutput: &coreV1.Service{
@@ -56,7 +54,7 @@ func TestCreateService(t *testing.T) {
                                        Namespace: namespace,
                                },
                        },
-                       expectedResult: internalVNFID + "-" + name,
+                       expectedResult: name,
                },
        }