From b2b175eae0f4e8b5b0cb9ccbeeca1e98065feeb5 Mon Sep 17 00:00:00 2001 From: Kiran Kamineni Date: Fri, 15 Mar 2019 15:18:12 -0700 Subject: Update definition and profile to latest spec Bringing all the definition and profile code upto the latest spec. Integrated the end to end instance code changes that were made. P9: Added updated plugin.sh with updated uri paths based on spec Issue-ID: MULTICLOUD-291 Change-Id: Id6e3c6bc2cd02cfb7005e203ccf03e0793b97e95 Signed-off-by: Kiran Kamineni --- kud/tests/plugin.sh | 65 ++-- src/k8splugin/api/api.go | 22 +- src/k8splugin/api/defhandler.go | 30 +- src/k8splugin/api/defhandler_test.go | 96 +++--- src/k8splugin/api/handler.go | 18 +- src/k8splugin/api/handler_test.go | 240 ++++++++++++++- src/k8splugin/api/model.go | 4 +- src/k8splugin/api/profilehandler.go | 57 +--- src/k8splugin/api/profilehandler_test.go | 146 ++------- src/k8splugin/internal/app/vnfhelper.go | 18 +- src/k8splugin/internal/app/vnfhelper_test.go | 31 +- src/k8splugin/internal/db/consul_test.go | 14 +- src/k8splugin/internal/db/mongo_test.go | 22 +- src/k8splugin/internal/db/testing.go | 4 +- src/k8splugin/internal/rb/definition.go | 95 +++--- src/k8splugin/internal/rb/definition_test.go | 171 ++++++----- src/k8splugin/internal/rb/profile.go | 166 +++++----- src/k8splugin/internal/rb/profile_test.go | 334 ++++++++++----------- .../mock_files/mock_json/create_rbdefinition.json | 8 +- .../mock_files/mock_json/create_rbprofile.json | 14 +- 20 files changed, 867 insertions(+), 688 deletions(-) diff --git a/kud/tests/plugin.sh b/kud/tests/plugin.sh index d632f844..2de55b61 100755 --- a/kud/tests/plugin.sh +++ b/kud/tests/plugin.sh @@ -18,11 +18,12 @@ source _functions.sh base_url="http://localhost:8081" cloud_region_id="kud" -namespace="testNS" +namespace="testns" csar_id="94e414f6-9ca4-11e8-bb6a-52540067263b" -rbd_csar_id="7eb09e38-4363-9942-1234-3beb2e95fd85" -definition_id="9d117af8-30b8-11e9-af94-525400277b3d" -profile_id="ebe353d2-30b7-11e9-9515-525400277b3d" +rb_name="test-rbdef" +rb_version="v1" +profile_name="profile1" +vnf_customization_uuid="ebe353d2-30b7-11e9-9515-525400277b3d" # _build_generic_sim() - Creates a generic simulator image in case that doesn't exist function _build_generic_sim { @@ -58,29 +59,31 @@ destroy_deployment $plugin_deployment_name #start_aai_service populate_CSAR_plugin $csar_id -populate_CSAR_rbdefinition $rbd_csar_id +populate_CSAR_rbdefinition $csar_id # Test print_msg "Create Resource Bundle Definition Metadata" payload_raw=" { - \"name\": \"test-rbdef\", + \"rb-name\": \"${rb_name}\", + \"rb-version\": \"${rb_version}\", \"chart-name\": \"vault-consul-dev\", \"description\": \"testing resource bundle definition api\", - \"uuid\": \"$definition_id\", - \"service-type\": \"firewall\" + \"labels\": { + \"vnf_customization_uuid\": \"${vnf_customization_uuid}\" + } } " payload=$(echo $payload_raw | tr '\n' ' ') -rbd_id=$(curl -s -d "$payload" -X POST "${base_url}/v1/rb/definition" | jq -r '.uuid') +rb_ret_name=$(curl -s -d "$payload" -X POST "${base_url}/v1/rb/definition" | jq -r '."rb-name"') print_msg "Upload Resource Bundle Definition Content" -curl -s --data-binary @${CSAR_DIR}/${rbd_csar_id}/${rbd_content_tarball}.gz -X POST "${base_url}/v1/rb/definition/$rbd_id/content" +curl -s --data-binary @${CSAR_DIR}/${csar_id}/${rbd_content_tarball}.gz -X POST "${base_url}/v1/rb/definition/$rb_name/$rb_version/content" print_msg "Listing Resource Bundle Definitions" -rbd_id_list=$(curl -s -X GET "${base_url}/v1/rb/definition") -if [[ "$rbd_id_list" != *"${rbd_id}"* ]]; then - echo $rbd_id_list +rb_list=$(curl -s -X GET "${base_url}/v1/rb/definition/$rb_name") +if [[ "$rb_list" != *"${rb_name}"* ]]; then + echo $rb_list echo "Resource Bundle Definition not stored" exit 1 fi @@ -89,23 +92,27 @@ print_msg "Create Resource Bundle Profile Metadata" kubeversion=$(kubectl version | grep 'Server Version' | awk -F '"' '{print $6}') payload_raw=" { - \"name\": \"test-rbprofile\", + \"profile-name\": \"${profile_name}\", + \"rb-name\": \"${rb_name}\", + \"rb-version\": \"${rb_version}\", + \"release-name\": \"testrelease\", \"namespace\": \"$namespace\", - \"rbdid\": \"$definition_id\", - \"uuid\": \"$profile_id\", - \"kubernetesversion\": \"$kubeversion\" + \"kubernetesversion\": \"$kubeversion\", + \"labels\": { + \"vnf_customization_uuid\": \"${vnf_customization_uuid}\" + } } " payload=$(echo $payload_raw | tr '\n' ' ') -rbp_id=$(curl -s -d "$payload" -X POST "${base_url}/v1/rb/profile" | jq -r '.uuid') +rbp_ret_name=$(curl -s -d "$payload" -X POST "${base_url}/v1/rb/definition/$rb_name/$rb_version/profile" | jq -r '."profile-name"') print_msg "Upload Resource Bundle Profile Content" -curl -s --data-binary @${CSAR_DIR}/${rbd_csar_id}/${rbp_content_tarball}.gz -X POST "${base_url}/v1/rb/profile/$rbp_id/content" +curl -s --data-binary @${CSAR_DIR}/${csar_id}/${rbp_content_tarball}.gz -X POST "${base_url}/v1/rb/definition/$rb_name/$rb_version/profile/$profile_name/content" -print_msg "Listing Resource Bundle Profiles" -rbp_id_list=$(curl -s -X GET "${base_url}/v1/rb/profile") -if [[ "$rbp_id_list" != *"${rbp_id}"* ]]; then - echo $rbd_id_list +print_msg "Getting Resource Bundle Profile" +rbp_ret=$(curl -s -X GET "${base_url}/v1/rb/definition/$rb_name/$rb_version/profile/$profile_name") +if [[ "$rbp_ret" != *"${profile_name}"* ]]; then + echo $rbp_ret echo "Resource Bundle Profile not stored" exit 1 fi @@ -114,7 +121,9 @@ print_msg "Instantiate Profile" payload_raw=" { \"cloud_region_id\": \"$cloud_region_id\", - \"rb_profile_id\":\"$profile_id\", + \"rb-name\":\"$rb_name\", + \"rb-version\":\"$rb_version\", + \"profile-name\":\"$profile_name\", \"csar_id\": \"$csar_id\" } " @@ -122,7 +131,7 @@ payload=$(echo $payload_raw | tr '\n' ' ') vnf_id=$(curl -s -d "$payload" "${base_url}/v1/vnf_instances/" | jq -r '.vnf_id') print_msg "Validating Kubernetes" -kubectl get --no-headers=true --namespace=${namespace} deployment ${cloud_region_id}-${namespace}-${vnf_id}-test-rbprofile-vault-consul-dev +kubectl get --no-headers=true --namespace=${namespace} deployment ${cloud_region_id}-${namespace}-${vnf_id}-testrelease-vault-consul-dev kubectl get --no-headers=true --namespace=${namespace} service ${cloud_region_id}-${namespace}-${vnf_id}-override-vault-consul echo "VNF Instance created succesfully with id: $vnf_id" @@ -142,9 +151,9 @@ if [[ -z "$vnf_details" ]]; then fi echo "VNF details $vnf_details" -print_msg "Deleting $rbd_id Resource Bundle Definition" -curl -X DELETE "${base_url}/v1/rb/definition/$rbd_id" -if [[ 500 -ne $(curl -o /dev/null -w %{http_code} -s -X GET "${base_url}/v1/rb/definition/$rbd_id") ]]; then +print_msg "Deleting $rb_name/$rb_version Resource Bundle Definition" +curl -X DELETE "${base_url}/v1/rb/definition/$rb_name/$rb_version" +if [[ 500 -ne $(curl -o /dev/null -w %{http_code} -s -X GET "${base_url}/v1/rb/definition/$rb_name/$rb_version") ]]; then echo "Resource Bundle Definition not deleted" # TODO: Change the HTTP code for 404 when the resource is not found in the API exit 1 diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go index 67a91282..2862a999 100644 --- a/src/k8splugin/api/api.go +++ b/src/k8splugin/api/api.go @@ -30,29 +30,27 @@ func NewRouter(kubeconfig string, defClient rb.DefinitionManager, vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", DeleteHandler).Methods("DELETE") vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", GetHandler).Methods("GET") - //rbd is resource bundle definition + //Setup resource bundle definition routes if defClient == nil { defClient = rb.NewDefinitionClient() } defHandler := rbDefinitionHandler{client: defClient} resRouter := router.PathPrefix("/v1/rb").Subrouter() resRouter.HandleFunc("/definition", defHandler.createHandler).Methods("POST") - resRouter.HandleFunc("/definition/{rbdID}/content", defHandler.uploadHandler).Methods("POST") - resRouter.HandleFunc("/definition", defHandler.listHandler).Methods("GET") - resRouter.HandleFunc("/definition/{rbdID}", defHandler.getHandler).Methods("GET") - resRouter.HandleFunc("/definition/{rbdID}", defHandler.deleteHandler).Methods("DELETE") + resRouter.HandleFunc("/definition/{rbname}/{rbversion}/content", defHandler.uploadHandler).Methods("POST") + resRouter.HandleFunc("/definition/{rbname}", defHandler.listVersionsHandler).Methods("GET") + resRouter.HandleFunc("/definition/{rbname}/{rbversion}", defHandler.getHandler).Methods("GET") + resRouter.HandleFunc("/definition/{rbname}/{rbversion}", defHandler.deleteHandler).Methods("DELETE") - //rbp is resource bundle profile + //Setup resource bundle profile routes if profileClient == nil { profileClient = rb.NewProfileClient() } profileHandler := rbProfileHandler{client: profileClient} - resRouter.HandleFunc("/profile", profileHandler.createHandler).Methods("POST") - resRouter.HandleFunc("/profile/{rbpID}/content", profileHandler.uploadHandler).Methods("POST") - resRouter.HandleFunc("/profile/help", profileHandler.helpHandler).Methods("GET") - resRouter.HandleFunc("/profile", profileHandler.listHandler).Methods("GET") - resRouter.HandleFunc("/profile/{rbpID}", profileHandler.getHandler).Methods("GET") - resRouter.HandleFunc("/profile/{rbpID}", profileHandler.deleteHandler).Methods("DELETE") + resRouter.HandleFunc("/definition/{rbname}/{rbversion}/profile", profileHandler.createHandler).Methods("POST") + resRouter.HandleFunc("/definition/{rbname}/{rbversion}/profile/{prname}/content", profileHandler.uploadHandler).Methods("POST") + 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") diff --git a/src/k8splugin/api/defhandler.go b/src/k8splugin/api/defhandler.go index f72247ab..93bbba15 100644 --- a/src/k8splugin/api/defhandler.go +++ b/src/k8splugin/api/defhandler.go @@ -54,6 +54,12 @@ func (h rbDefinitionHandler) createHandler(w http.ResponseWriter, r *http.Reques return } + // Version is required. + if v.Version == "" { + http.Error(w, "Missing version in POST request", http.StatusBadRequest) + return + } + ret, err := h.client.Create(v) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -72,7 +78,8 @@ func (h rbDefinitionHandler) createHandler(w http.ResponseWriter, r *http.Reques // uploadHandler handles upload of the bundle tar file into the database func (h rbDefinitionHandler) uploadHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - uuid := vars["rbdID"] + name := vars["rbname"] + version := vars["rbversion"] inpBytes, err := ioutil.ReadAll(r.Body) if err != nil { @@ -85,7 +92,7 @@ func (h rbDefinitionHandler) uploadHandler(w http.ResponseWriter, r *http.Reques return } - err = h.client.Upload(uuid, inpBytes) + err = h.client.Upload(name, version, inpBytes) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -94,10 +101,13 @@ func (h rbDefinitionHandler) uploadHandler(w http.ResponseWriter, r *http.Reques w.WriteHeader(http.StatusOK) } -// listHandler handles GET (list) operations on the endpoint +// listVersionsHandler handles GET (list) operations on the endpoint // Returns a list of rb.Definitions -func (h rbDefinitionHandler) listHandler(w http.ResponseWriter, r *http.Request) { - ret, err := h.client.List() +func (h rbDefinitionHandler) listVersionsHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["rbname"] + + ret, err := h.client.List(name) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -116,9 +126,10 @@ func (h rbDefinitionHandler) listHandler(w http.ResponseWriter, r *http.Request) // Returns a rb.Definition func (h rbDefinitionHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - id := vars["rbdID"] + name := vars["rbname"] + version := vars["rbversion"] - ret, err := h.client.Get(id) + ret, err := h.client.Get(name, version) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -136,9 +147,10 @@ func (h rbDefinitionHandler) getHandler(w http.ResponseWriter, r *http.Request) // deleteHandler handles DELETE operations on a particular bundle definition id func (h rbDefinitionHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - id := vars["rbdID"] + name := vars["rbname"] + version := vars["rbversion"] - err := h.client.Delete(id) + err := h.client.Delete(name, version) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/k8splugin/api/defhandler_test.go b/src/k8splugin/api/defhandler_test.go index ed5f298b..9d727fb7 100644 --- a/src/k8splugin/api/defhandler_test.go +++ b/src/k8splugin/api/defhandler_test.go @@ -49,7 +49,7 @@ func (m *mockRBDefinition) Create(inp rb.Definition) (rb.Definition, error) { return m.Items[0], nil } -func (m *mockRBDefinition) List() ([]rb.Definition, error) { +func (m *mockRBDefinition) List(name string) ([]rb.Definition, error) { if m.Err != nil { return []rb.Definition{}, m.Err } @@ -57,7 +57,7 @@ func (m *mockRBDefinition) List() ([]rb.Definition, error) { return m.Items, nil } -func (m *mockRBDefinition) Get(id string) (rb.Definition, error) { +func (m *mockRBDefinition) Get(name, version string) (rb.Definition, error) { if m.Err != nil { return rb.Definition{}, m.Err } @@ -65,11 +65,11 @@ func (m *mockRBDefinition) Get(id string) (rb.Definition, error) { return m.Items[0], nil } -func (m *mockRBDefinition) Delete(id string) error { +func (m *mockRBDefinition) Delete(name, version string) error { return m.Err } -func (m *mockRBDefinition) Upload(id string, inp []byte) error { +func (m *mockRBDefinition) Upload(name, version string, inp []byte) error { return m.Err } @@ -87,30 +87,28 @@ func TestRBDefCreateHandler(t *testing.T) { rbDefClient: &mockRBDefinition{}, }, { - label: "Create without UUID", + label: "Create Definition", expectedCode: http.StatusCreated, reader: bytes.NewBuffer([]byte(`{ - "name":"testresourcebundle", + "rb-name":"testresourcebundle", + "rb-version":"v1", "chart-name":"testchart", - "description":"test description", - "service-type":"firewall" + "description":"test description" }`)), expected: rb.Definition{ - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", ChartName: "testchart", Description: "test description", - ServiceType: "firewall", }, rbDefClient: &mockRBDefinition{ //Items that will be returned by the mocked Client Items: []rb.Definition{ { - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", ChartName: "testchart", Description: "test description", - ServiceType: "firewall", }, }, }, @@ -118,9 +116,19 @@ func TestRBDefCreateHandler(t *testing.T) { { label: "Missing Name in Request Body", reader: bytes.NewBuffer([]byte(`{ + "rb-version":"v1", "chart-name":"testchart", - "description":"test description", - "service-type":"firewall" + "description":"test description" + }`)), + expectedCode: http.StatusBadRequest, + rbDefClient: &mockRBDefinition{}, + }, + { + label: "Missing Version in Request Body", + reader: bytes.NewBuffer([]byte(`{ + "rb-name":"testresourcebundle", + "chart-name":"testchart", + "description":"test description" }`)), expectedCode: http.StatusBadRequest, rbDefClient: &mockRBDefinition{}, @@ -154,7 +162,7 @@ func TestRBDefCreateHandler(t *testing.T) { } } -func TestRBDefListHandler(t *testing.T) { +func TestRBDefListVersionsHandler(t *testing.T) { testCases := []struct { label string @@ -167,32 +175,32 @@ func TestRBDefListHandler(t *testing.T) { expectedCode: http.StatusOK, expected: []rb.Definition{ { - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", + ChartName: "testchart", Description: "test description", - ServiceType: "firewall", }, { - UUID: "123e4567-e89b-12d3-a456-426655441111", - Name: "testresourcebundle2", + Name: "testresourcebundle", + Version: "v2", + ChartName: "testchart", Description: "test description", - ServiceType: "dns", }, }, rbDefClient: &mockRBDefinition{ // list of definitions that will be returned by the mockclient Items: []rb.Definition{ { - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", + ChartName: "testchart", Description: "test description", - ServiceType: "firewall", }, { - UUID: "123e4567-e89b-12d3-a456-426655441111", - Name: "testresourcebundle2", + Name: "testresourcebundle", + Version: "v2", + ChartName: "testchart", Description: "test description", - ServiceType: "dns", }, }, }, @@ -202,9 +210,9 @@ func TestRBDefListHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { vh := rbDefinitionHandler{client: testCase.rbDefClient} - req := httptest.NewRequest("GET", "/v1/rb/definition", nil) + req := httptest.NewRequest("GET", "/v1/rb/definition/testresourcebundle", nil) rr := httptest.NewRecorder() - vh.listHandler(rr, req) + vh.listVersionsHandler(rr, req) resp := rr.Result() //Check returned code @@ -220,12 +228,12 @@ func TestRBDefListHandler(t *testing.T) { // Since the order of returned slice is not guaranteed // Check both and return error if both don't match sort.Slice(got, func(i, j int) bool { - return got[i].UUID < got[j].UUID + return got[i].Version < got[j].Version }) // Sort both as it is not expected that testCase.expected // is sorted sort.Slice(testCase.expected, func(i, j int) bool { - return testCase.expected[i].UUID < testCase.expected[j].UUID + return testCase.expected[i].Version < testCase.expected[j].Version }) if reflect.DeepEqual(testCase.expected, got) == false { @@ -240,30 +248,31 @@ func TestRBDefListHandler(t *testing.T) { func TestRBDefGetHandler(t *testing.T) { testCases := []struct { - label string - expected rb.Definition - inpUUID string - expectedCode int - rbDefClient *mockRBDefinition + label string + expected rb.Definition + name, version string + expectedCode int + rbDefClient *mockRBDefinition }{ { label: "Get Bundle Definition", expectedCode: http.StatusOK, expected: rb.Definition{ - UUID: "123e4567-e89b-12d3-a456-426655441111", - Name: "testresourcebundle2", + Name: "testresourcebundle", + Version: "v1", + ChartName: "testchart", Description: "test description", - ServiceType: "dns", }, - inpUUID: "123e4567-e89b-12d3-a456-426655441111", + name: "testresourcebundle", + version: "v1", rbDefClient: &mockRBDefinition{ // list of definitions that will be returned by the mockclient Items: []rb.Definition{ { - UUID: "123e4567-e89b-12d3-a456-426655441111", - Name: "testresourcebundle2", + Name: "testresourcebundle", + Version: "v1", + ChartName: "testchart", Description: "test description", - ServiceType: "dns", }, }, }, @@ -271,7 +280,8 @@ func TestRBDefGetHandler(t *testing.T) { { label: "Get Non-Exiting Bundle Definition", expectedCode: http.StatusInternalServerError, - inpUUID: "123e4567-e89b-12d3-a456-426655440000", + name: "nonexistingbundle", + version: "v1", rbDefClient: &mockRBDefinition{ // list of definitions that will be returned by the mockclient Items: []rb.Definition{}, @@ -283,7 +293,7 @@ func TestRBDefGetHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { vh := rbDefinitionHandler{client: testCase.rbDefClient} - req := httptest.NewRequest("GET", "/v1/rb/definition/"+testCase.inpUUID, nil) + req := httptest.NewRequest("GET", "/v1/rb/definition/"+testCase.name+"/"+testCase.version, nil) rr := httptest.NewRecorder() vh.getHandler(rr, req) resp := rr.Result() diff --git a/src/k8splugin/api/handler.go b/src/k8splugin/api/handler.go index b1cc6709..31ffad90 100644 --- a/src/k8splugin/api/handler.go +++ b/src/k8splugin/api/handler.go @@ -63,8 +63,12 @@ func validateBody(body interface{}) error { werr := pkgerrors.Wrap(errors.New("Invalid/Missing CsarID in POST request"), "CreateVnfRequest bad request") return werr } - if b.RBProfileID == "" { - werr := pkgerrors.Wrap(errors.New("Invalid/Missing RB ProfileID in POST request"), "CreateVnfRequest bad request") + 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, "|") { @@ -117,16 +121,20 @@ func CreateHandler(w http.ResponseWriter, r *http.Request) { }, 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, - resource.RBProfileID, &kubeclient) + profile, &kubeclient) if err != nil { werr := pkgerrors.Wrap(err, "Read Kubernetes Data information error") http.Error(w, werr.Error(), http.StatusInternalServerError) return } - rbProfile, _ := rb.NewProfileClient().Get(resource.RBProfileID) - namespace := rbProfile.Namespace + namespace := profile.Namespace // cloud1-default-uuid internalVNFID := resource.CloudRegionID + "-" + namespace + "-" + externalVNFID diff --git a/src/k8splugin/api/handler_test.go b/src/k8splugin/api/handler_test.go index d1e4de07..ee4a3005 100644 --- a/src/k8splugin/api/handler_test.go +++ b/src/k8splugin/api/handler_test.go @@ -29,6 +29,7 @@ import ( helper "k8splugin/internal/app" "k8splugin/internal/db" + "k8splugin/internal/rb" ) type mockCSAR struct { @@ -37,7 +38,7 @@ type mockCSAR struct { err error } -func (c *mockCSAR) CreateVNF(id, r, n string, +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 } @@ -83,12 +84,14 @@ func TestCreateHandler(t *testing.T) { label: "Missing parameter failure", input: bytes.NewBuffer([]byte(`{ "csar_id": "testID", - "oof_parameters": { + "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" }`)), @@ -98,6 +101,9 @@ func TestCreateHandler(t *testing.T) { 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" }`)), @@ -108,6 +114,9 @@ func TestCreateHandler(t *testing.T) { 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" }`)), @@ -115,11 +124,123 @@ func TestCreateHandler(t *testing.T) { mockCreateVNF: &mockCSAR{ err: pkgerrors.New("Internal error"), }, + mockStore: &db.MockDB{ + Items: map[string]map[string][]byte{ + rb.ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", + Name: "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("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" + + "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" }`)), @@ -135,6 +256,9 @@ func TestCreateHandler(t *testing.T) { 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" }`)), @@ -145,7 +269,115 @@ func TestCreateHandler(t *testing.T) { "service": []string{"cloud1-default-uuid-sisesvc"}, }, }, - mockStore: &db.MockDB{}, + mockStore: &db.MockDB{ + Items: map[string]map[string][]byte{ + rb.ProfileKey{RBName: "test-rbdef", RBVersion: "v1", + Name: "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=="), + }, + }, + }, }, } diff --git a/src/k8splugin/api/model.go b/src/k8splugin/api/model.go index 164143c2..1a3abed5 100644 --- a/src/k8splugin/api/model.go +++ b/src/k8splugin/api/model.go @@ -17,7 +17,9 @@ package api type CreateVnfRequest struct { CloudRegionID string `json:"cloud_region_id"` CsarID string `json:"csar_id"` - RBProfileID string `json:"rb_profile_id"` + RBName string `json:"rb-name"` + RBVersion string `json:"rb-version"` + ProfileName string `json:"profile-name"` OOFParams []map[string]interface{} `json:"oof_parameters"` NetworkParams NetworkParameters `json:"network_parameters"` Name string `json:"vnf_instance_name"` diff --git a/src/k8splugin/api/profilehandler.go b/src/k8splugin/api/profilehandler.go index 267dae0e..2c15a440 100644 --- a/src/k8splugin/api/profilehandler.go +++ b/src/k8splugin/api/profilehandler.go @@ -36,9 +36,9 @@ type rbProfileHandler struct { // createHandler handles creation of the definition entry in the database func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) { - var v rb.Profile + var p rb.Profile - err := json.NewDecoder(r.Body).Decode(&v) + err := json.NewDecoder(r.Body).Decode(&p) switch { case err == io.EOF: http.Error(w, "Empty body", http.StatusBadRequest) @@ -49,18 +49,12 @@ func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) } // Name is required. - if v.Name == "" { + if p.Name == "" { http.Error(w, "Missing name in POST request", http.StatusBadRequest) return } - // Definition ID is required - if v.RBDID == "" { - http.Error(w, "Missing Resource Bundle Definition ID in POST request", http.StatusBadRequest) - return - } - - ret, err := h.client.Create(v) + ret, err := h.client.Create(p) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -78,7 +72,9 @@ func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) // uploadHandler handles upload of the bundle tar file into the database func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - uuid := vars["rbpID"] + rbName := vars["rbname"] + rbVersion := vars["rbversion"] + prName := vars["prname"] inpBytes, err := ioutil.ReadAll(r.Body) if err != nil { @@ -91,37 +87,12 @@ func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request) return } - err = h.client.Upload(uuid, inpBytes) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -} - -// listHandler handles GET (list) operations on the endpoint -// Returns a list of rb.Definitions -func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) { - ret, err := h.client.List() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - err = json.NewEncoder(w).Encode(ret) + err = h.client.Upload(rbName, rbVersion, prName, inpBytes) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } -} -// helpHandler handles GET (list) operations on the endpoint -// Returns a list of rb.Definitions -func (h rbProfileHandler) helpHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) } @@ -129,9 +100,11 @@ func (h rbProfileHandler) helpHandler(w http.ResponseWriter, r *http.Request) { // Returns a rb.Definition func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - id := vars["rbpID"] + rbName := vars["rbname"] + rbVersion := vars["rbversion"] + prName := vars["prname"] - ret, err := h.client.Get(id) + ret, err := h.client.Get(rbName, rbVersion, prName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -149,9 +122,11 @@ func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) { // deleteHandler handles DELETE operations on a particular bundle definition id func (h rbProfileHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - id := vars["rbpID"] + rbName := vars["rbname"] + rbVersion := vars["rbversion"] + prName := vars["prname"] - err := h.client.Delete(id) + err := h.client.Delete(rbName, rbVersion, prName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/k8splugin/api/profilehandler_test.go b/src/k8splugin/api/profilehandler_test.go index f6b27fc4..4e346862 100644 --- a/src/k8splugin/api/profilehandler_test.go +++ b/src/k8splugin/api/profilehandler_test.go @@ -24,7 +24,6 @@ import ( "net/http" "net/http/httptest" "reflect" - "sort" "testing" pkgerrors "github.com/pkg/errors" @@ -49,15 +48,7 @@ func (m *mockRBProfile) Create(inp rb.Profile) (rb.Profile, error) { return m.Items[0], nil } -func (m *mockRBProfile) List() ([]rb.Profile, error) { - if m.Err != nil { - return []rb.Profile{}, m.Err - } - - return m.Items, nil -} - -func (m *mockRBProfile) Get(id string) (rb.Profile, error) { +func (m *mockRBProfile) Get(rbname, rbversion, prname string) (rb.Profile, error) { if m.Err != nil { return rb.Profile{}, m.Err } @@ -65,11 +56,11 @@ func (m *mockRBProfile) Get(id string) (rb.Profile, error) { return m.Items[0], nil } -func (m *mockRBProfile) Delete(id string) error { +func (m *mockRBProfile) Delete(rbname, rbversion, prname string) error { return m.Err } -func (m *mockRBProfile) Upload(id string, inp []byte) error { +func (m *mockRBProfile) Upload(rbname, rbversion, prname string, inp []byte) error { return m.Err } @@ -85,20 +76,24 @@ func TestRBProfileCreateHandler(t *testing.T) { label: "Missing Body Failure", expectedCode: http.StatusBadRequest, rbDefClient: &mockRBProfile{}, + reader: nil, }, { - label: "Create without UUID", + label: "Create New Profile for Definition", expectedCode: http.StatusCreated, reader: bytes.NewBuffer([]byte(`{ - "rbdid":"abcde123-e89b-8888-a456-986655447236", - "name":"testdomain", + "rb-name":"testresource_bundle_definition", + "rb-version":"v1", + "profile-name":"profile1", + "release-name":"testprofilereleasename", "namespace":"default", - "kubernetesversion":"1.12.3" + "kubernetes-version":"1.12.3" }`)), expected: rb.Profile{ - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", + RBName: "testresource_bundle_definition", + RBVersion: "v1", + Name: "profile1", + ReleaseName: "testprofilereleasename", Namespace: "default", KubernetesVersion: "1.12.3", }, @@ -106,9 +101,10 @@ func TestRBProfileCreateHandler(t *testing.T) { //Items that will be returned by the mocked Client Items: []rb.Profile{ { - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", + RBName: "testresource_bundle_definition", + RBVersion: "v1", + Name: "profile1", + ReleaseName: "testprofilereleasename", Namespace: "default", KubernetesVersion: "1.12.3", }, @@ -120,7 +116,8 @@ func TestRBProfileCreateHandler(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.label, func(t *testing.T) { vh := rbProfileHandler{client: testCase.rbDefClient} - req := httptest.NewRequest("POST", "/v1/rb/profile", testCase.reader) + req := httptest.NewRequest("POST", "/v1/rb/profile/testresource_bundle_definition/v1/profile", + testCase.reader) rr := httptest.NewRecorder() vh.createHandler(rr, req) resp := rr.Result() @@ -144,93 +141,6 @@ func TestRBProfileCreateHandler(t *testing.T) { } } -func TestRBProfileListHandler(t *testing.T) { - - testCases := []struct { - label string - expected []rb.Profile - expectedCode int - rbDefClient *mockRBProfile - }{ - { - label: "List Bundle Profiles", - expectedCode: http.StatusOK, - expected: []rb.Profile{ - { - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", - KubernetesVersion: "1.12.3", - }, - { - UUID: "123e4567-e89b-12d3-a456-426655441111", - RBDID: "abcde123-e89b-8888-a456-986655441111", - Name: "testresourcebundle2", - Namespace: "default", - KubernetesVersion: "1.12.3", - }, - }, - rbDefClient: &mockRBProfile{ - // list of Profiles that will be returned by the mockclient - Items: []rb.Profile{ - { - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", - KubernetesVersion: "1.12.3", - }, - { - UUID: "123e4567-e89b-12d3-a456-426655441111", - RBDID: "abcde123-e89b-8888-a456-986655441111", - Name: "testresourcebundle2", - Namespace: "default", - KubernetesVersion: "1.12.3", - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - vh := rbProfileHandler{client: testCase.rbDefClient} - req := httptest.NewRequest("GET", "/v1/rb/profile", nil) - rr := httptest.NewRecorder() - vh.listHandler(rr, req) - - resp := rr.Result() - //Check returned code - if resp.StatusCode != testCase.expectedCode { - t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode) - } - - //Check returned body only if statusOK - if resp.StatusCode == http.StatusOK { - got := []rb.Profile{} - json.NewDecoder(resp.Body).Decode(&got) - - // Since the order of returned slice is not guaranteed - // Check both and return error if both don't match - sort.Slice(got, func(i, j int) bool { - return got[i].UUID < got[j].UUID - }) - // Sort both as it is not expected that testCase.expected - // is sorted - sort.Slice(testCase.expected, func(i, j int) bool { - return testCase.expected[i].UUID < testCase.expected[j].UUID - }) - - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("listHandler returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - func TestRBProfileGetHandler(t *testing.T) { testCases := []struct { @@ -244,20 +154,22 @@ func TestRBProfileGetHandler(t *testing.T) { label: "Get Bundle Profile", expectedCode: http.StatusOK, expected: rb.Profile{ - UUID: "123e4567-e89b-12d3-a456-426655441111", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle2", + RBName: "testresource_bundle_definition", + RBVersion: "v1", + Name: "profile1", + ReleaseName: "testprofilereleasename", Namespace: "default", KubernetesVersion: "1.12.3", }, inpUUID: "123e4567-e89b-12d3-a456-426655441111", rbDefClient: &mockRBProfile{ - // list of Profiles that will be returned by the mockclient + // Profile that will be returned by the mockclient Items: []rb.Profile{ { - UUID: "123e4567-e89b-12d3-a456-426655441111", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle2", + RBName: "testresource_bundle_definition", + RBVersion: "v1", + Name: "profile1", + ReleaseName: "testprofilereleasename", Namespace: "default", KubernetesVersion: "1.12.3", }, diff --git a/src/k8splugin/internal/app/vnfhelper.go b/src/k8splugin/internal/app/vnfhelper.go index 5984bbd0..0a867090 100644 --- a/src/k8splugin/internal/app/vnfhelper.go +++ b/src/k8splugin/internal/app/vnfhelper.go @@ -70,23 +70,17 @@ func ensuresNamespace(namespace string, kubeclient kubernetes.Interface) error { } // CreateVNF reads the CSAR files from the files system and creates them one by one -var CreateVNF = func(csarID string, cloudRegionID string, rbProfileID string, kubeclient *kubernetes.Clientset) (string, map[string][]string, error) { +var CreateVNF = func(csarID string, cloudRegionID string, profile rb.Profile, kubeclient *kubernetes.Clientset) (string, map[string][]string, error) { overrideValues := []string{} - rbProfileClient := rb.NewProfileClient() - rbProfile, err := rbProfileClient.Get(rbProfileID) - if err != nil { - return "", nil, pkgerrors.Wrap(err, "Error getting profile info") - } - //Make sure that the namespace exists before trying to create any resources - if err := ensuresNamespace(rbProfile.Namespace, kubeclient); err != nil { - return "", nil, pkgerrors.Wrap(err, "Error while ensuring namespace: "+rbProfile.Namespace) + if err := ensuresNamespace(profile.Namespace, kubeclient); err != nil { + return "", nil, pkgerrors.Wrap(err, "Error while ensuring namespace: "+profile.Namespace) } externalVNFID := generateExternalVNFID() - internalVNFID := cloudRegionID + "-" + rbProfile.Namespace + "-" + externalVNFID + internalVNFID := cloudRegionID + "-" + profile.Namespace + "-" + externalVNFID - metaMap, err := rb.NewProfileClient().Resolve(rbProfileID, overrideValues) + metaMap, err := rb.NewProfileClient().Resolve(profile.RBName, profile.RBVersion, profile.Name, overrideValues) if err != nil { return "", nil, pkgerrors.Wrap(err, "Error resolving helm charts") } @@ -109,7 +103,7 @@ var CreateVNF = func(csarID string, cloudRegionID string, rbProfileID string, ku //Populate the namespace from profile instead of instance body genericKubeData := &utils.ResourceData{ YamlFilePath: filepath, - Namespace: rbProfile.Namespace, + Namespace: profile.Namespace, VnfId: internalVNFID, } diff --git a/src/k8splugin/internal/app/vnfhelper_test.go b/src/k8splugin/internal/app/vnfhelper_test.go index 0bd21f72..06866150 100644 --- a/src/k8splugin/internal/app/vnfhelper_test.go +++ b/src/k8splugin/internal/app/vnfhelper_test.go @@ -28,6 +28,7 @@ import ( utils "k8splugin/internal" "k8splugin/internal/db" + "k8splugin/internal/rb" ) func LoadMockPlugins(krdLoadedPlugins *map[string]*plugin.Plugin) error { @@ -84,12 +85,14 @@ func TestCreateVNF(t *testing.T) { t.Run("Successfully create VNF", func(t *testing.T) { db.DBconn = &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + rb.ProfileKey{RBName: "test-rbdef", RBVersion: "v1", + Name: "profile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"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" + @@ -116,13 +119,12 @@ func TestCreateVNF(t *testing.T) { "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" + "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA="), }, - "abcde123-e89b-8888-a456-986655447236": { + rb.DefinitionKey{Name: "test-rbdef", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"test-rbdef\"," + + "\"rb-version\":\"v1\"," + "\"chart-name\":\"vault-consul-dev\"," + - "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"abcde123-e89b-8888-a456-986655447236\"," + - "\"service-type\":\"firewall\"}"), + "\"description\":\"testresourcebundle\"}"), // base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev "content": []byte("H4sICEetS1wAA3ZhdWx0LWNvbnN1bC1kZXYudGFyAO0c7XLbNjK/+R" + "QYujdJehatb+V4czPnOmnPk9bO2Gk7nbaTgUhIxpgiGAK0o3P9QPca92S3C5AU9GXZiax" + @@ -191,7 +193,14 @@ func TestCreateVNF(t *testing.T) { }, } externaluuid, data, err := CreateVNF("uuid", "cloudregion1", - "123e4567-e89b-12d3-a456-426655440000", &kubeclient) + rb.Profile{ + RBName: "test-rbdef", + RBVersion: "v1", + Name: "profile1", + ReleaseName: "testprofilereleasename", + Namespace: "testnamespace", + KubernetesVersion: "1.12.3", + }, &kubeclient) if err != nil { t.Fatalf("TestCreateVNF returned an error (%s)", err) } diff --git a/src/k8splugin/internal/db/consul_test.go b/src/k8splugin/internal/db/consul_test.go index 6d127841..abd264c8 100644 --- a/src/k8splugin/internal/db/consul_test.go +++ b/src/k8splugin/internal/db/consul_test.go @@ -108,13 +108,13 @@ func TestConsulCreate(t *testing.T) { }{ { label: "Sucessful register a record to Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, input: map[string]string{"root": "rbinst", "tag": "data", "value": "test-value"}, mock: &mockConsulKVStore{}, }, { label: "Fail to create a new record in Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, input: map[string]string{"root": "rbinst", "tag": "data", "value": "test-value"}, mock: &mockConsulKVStore{ Err: pkgerrors.New("DB error"), @@ -151,7 +151,7 @@ func TestConsulRead(t *testing.T) { }{ { label: "Sucessful retrieve a record from Consul Database", - key: mockKey{Key: "test"}, + key: MockKey{Key: "test"}, input: map[string]string{"root": "rbinst", "tag": "data"}, mock: &mockConsulKVStore{ Items: api.KVPairs{ @@ -165,13 +165,13 @@ func TestConsulRead(t *testing.T) { }, { label: "Fail retrieve a non-existing record from Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, input: map[string]string{"root": "rbinst", "tag": "data"}, mock: &mockConsulKVStore{}, }, { label: "Fail retrieve a record from Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, input: map[string]string{"root": "rbinst", "tag": "data"}, mock: &mockConsulKVStore{ Err: pkgerrors.New("DB error"), @@ -215,13 +215,13 @@ func TestConsulDelete(t *testing.T) { }{ { label: "Sucessful delete a record to Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, input: map[string]string{"root": "rbinst", "tag": "data"}, mock: &mockConsulKVStore{}, }, { label: "Fail to delete a record in Consul Database", - key: mockKey{Key: "test-key"}, + key: MockKey{Key: "test-key"}, mock: &mockConsulKVStore{ Err: pkgerrors.New("DB error"), }, diff --git a/src/k8splugin/internal/db/mongo_test.go b/src/k8splugin/internal/db/mongo_test.go index deb51044..baa442ce 100644 --- a/src/k8splugin/internal/db/mongo_test.go +++ b/src/k8splugin/internal/db/mongo_test.go @@ -84,7 +84,7 @@ func TestCreate(t *testing.T) { label: "Successfull creation of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "tagName", "data": "Data In String Format", }, @@ -95,7 +95,7 @@ func TestCreate(t *testing.T) { label: "UnSuccessfull creation of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "tagName", "data": "Data In String Format", }, @@ -108,7 +108,7 @@ func TestCreate(t *testing.T) { label: "Missing input fields", input: map[string]interface{}{ "coll": "", - "key": mockKey{Key: ""}, + "key": MockKey{Key: ""}, "tag": "", "data": "", }, @@ -156,7 +156,7 @@ func TestRead(t *testing.T) { label: "Successfull Read of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "metadata", }, // Binary form of @@ -186,7 +186,7 @@ func TestRead(t *testing.T) { label: "UnSuccessfull Read of entry: object not found", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "badtag", }, // Binary form of @@ -215,7 +215,7 @@ func TestRead(t *testing.T) { label: "UnSuccessfull Read of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "tagName", }, mockColl: &mockCollection{ @@ -227,7 +227,7 @@ func TestRead(t *testing.T) { label: "Missing input fields", input: map[string]interface{}{ "coll": "", - "key": mockKey{Key: ""}, + "key": MockKey{Key: ""}, "tag": "", }, expectedError: "Mandatory fields are missing", @@ -277,7 +277,7 @@ func TestDelete(t *testing.T) { label: "Successfull Delete of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "metadata", }, // Binary form of @@ -305,7 +305,7 @@ func TestDelete(t *testing.T) { label: "UnSuccessfull Delete of entry", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "tagName", }, mockColl: &mockCollection{ @@ -317,7 +317,7 @@ func TestDelete(t *testing.T) { label: "UnSuccessfull Delete, key not found", input: map[string]interface{}{ "coll": "collname", - "key": mockKey{Key: "keyvalue"}, + "key": MockKey{Key: "keyvalue"}, "tag": "tagName", }, // Binary form of @@ -346,7 +346,7 @@ func TestDelete(t *testing.T) { label: "Missing input fields", input: map[string]interface{}{ "coll": "", - "key": mockKey{Key: ""}, + "key": MockKey{Key: ""}, "tag": "", }, expectedError: "Mandatory fields are missing", diff --git a/src/k8splugin/internal/db/testing.go b/src/k8splugin/internal/db/testing.go index a411790e..e7e7436a 100644 --- a/src/k8splugin/internal/db/testing.go +++ b/src/k8splugin/internal/db/testing.go @@ -20,11 +20,11 @@ import ( pkgerrors "github.com/pkg/errors" ) -type mockKey struct { +type MockKey struct { Key string } -func (m mockKey) String() string { +func (m MockKey) String() string { return m.Key } diff --git a/src/k8splugin/internal/rb/definition.go b/src/k8splugin/internal/rb/definition.go index 2ebbb08a..1c6b1bc5 100644 --- a/src/k8splugin/internal/rb/definition.go +++ b/src/k8splugin/internal/rb/definition.go @@ -19,6 +19,7 @@ package rb import ( "bytes" "encoding/base64" + "encoding/json" "io/ioutil" "log" "os" @@ -26,35 +27,42 @@ import ( "k8splugin/internal/db" - uuid "github.com/hashicorp/go-uuid" pkgerrors "github.com/pkg/errors" ) // Definition contains the parameters needed for resource bundle (rb) definitions // It implements the interface for managing the definitions type Definition struct { - UUID string `json:"uuid,omitempty"` - Name string `json:"name"` - ChartName string `json:"chart-name"` - Description string `json:"description"` - ServiceType string `json:"service-type"` + Name string `json:"rb-name"` + Version string `json:"rb-version"` + ChartName string `json:"chart-name"` + Description string `json:"description"` + Labels map[string]string `json:"labels"` } -// DefinitionManager is an interface exposes the resource bundle definition functionality -type DefinitionManager interface { - Create(def Definition) (Definition, error) - List() ([]Definition, error) - Get(resID string) (Definition, error) - Delete(resID string) error - Upload(resID string, inp []byte) error +type DefinitionKey struct { + Name string `json:"rb-name"` + Version string `json:"rb-version"` } -type definitionKey struct { - Key string +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (dk DefinitionKey) String() string { + out, err := json.Marshal(dk) + if err != nil { + return "" + } + + return string(out) } -func (dk definitionKey) String() string { - return dk.Key +// DefinitionManager is an interface exposes the resource bundle definition functionality +type DefinitionManager interface { + Create(def Definition) (Definition, error) + List(name string) ([]Definition, error) + Get(name string, version string) (Definition, error) + Delete(name string, version string) error + Upload(name string, version string, inp []byte) error } // DefinitionClient implements the DefinitionManager @@ -77,13 +85,17 @@ func NewDefinitionClient() *DefinitionClient { // Create an entry for the resource in the database func (v *DefinitionClient) Create(def Definition) (Definition, error) { - // If UUID is empty, we will generate one - if def.UUID == "" { - def.UUID, _ = uuid.GenerateUUID() + + //Construct composite key consisting of name and version + key := DefinitionKey{Name: def.Name, Version: def.Version} + + //Check if this definition already exists + _, err := v.Get(def.Name, def.Version) + if err == nil { + return Definition{}, pkgerrors.New("Definition already exists") } - key := definitionKey{Key: def.UUID} - err := db.DBconn.Create(v.storeName, key, v.tagMeta, def) + err = db.DBconn.Create(v.storeName, key, v.tagMeta, def) if err != nil { return Definition{}, pkgerrors.Wrap(err, "Creating DB Entry") } @@ -91,8 +103,8 @@ func (v *DefinitionClient) Create(def Definition) (Definition, error) { return def, nil } -// List all resource entries in the database -func (v *DefinitionClient) List() ([]Definition, error) { +// List all resource entry's versions in the database +func (v *DefinitionClient) List(name string) ([]Definition, error) { res, err := db.DBconn.ReadAll(v.storeName, v.tagMeta) if err != nil || len(res) == 0 { return []Definition{}, pkgerrors.Wrap(err, "Listing Resource Bundle Definitions") @@ -108,7 +120,10 @@ func (v *DefinitionClient) List() ([]Definition, error) { log.Printf("[Definition] Error Unmarshaling value for: %s", key) continue } - results = append(results, def) + //Select only the definitions that match name provided + if def.Name == name { + results = append(results, def) + } } } @@ -116,8 +131,10 @@ func (v *DefinitionClient) List() ([]Definition, error) { } // Get returns the Resource Bundle Definition for corresponding ID -func (v *DefinitionClient) Get(id string) (Definition, error) { - key := definitionKey{Key: id} +func (v *DefinitionClient) Get(name string, version string) (Definition, error) { + + //Construct the composite key to select the entry + key := DefinitionKey{Name: name, Version: version} value, err := db.DBconn.Read(v.storeName, key, v.tagMeta) if err != nil { return Definition{}, pkgerrors.Wrap(err, "Get Resource Bundle definition") @@ -137,8 +154,10 @@ func (v *DefinitionClient) Get(id string) (Definition, error) { } // Delete the Resource Bundle definition from database -func (v *DefinitionClient) Delete(id string) error { - key := definitionKey{Key: id} +func (v *DefinitionClient) Delete(name string, version string) error { + + //Construct the composite key to select the entry + key := DefinitionKey{Name: name, Version: version} err := db.DBconn.Delete(v.storeName, key, v.tagMeta) if err != nil { return pkgerrors.Wrap(err, "Delete Resource Bundle Definition") @@ -154,11 +173,10 @@ func (v *DefinitionClient) Delete(id string) error { } // Upload the contents of resource bundle into database -func (v *DefinitionClient) Upload(id string, inp []byte) error { +func (v *DefinitionClient) Upload(name string, version string, inp []byte) error { - key := definitionKey{Key: id} //Check if definition metadata exists - def, err := v.Get(id) + def, err := v.Get(name, version) if err != nil { return pkgerrors.Errorf("Invalid Definition ID provided: %s", err.Error()) } @@ -168,6 +186,9 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error { return pkgerrors.Errorf("Error in file format: %s", err.Error()) } + //Construct the composite key to select the entry + key := DefinitionKey{Name: name, Version: version} + //Detect chart name from data if it was not provided originally if def.ChartName == "" { path, err := ExtractTarBall(bytes.NewBuffer(inp)) @@ -195,7 +216,8 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error { return pkgerrors.New("Unable to detect chart name") } - _, err = v.Create(def) + //TODO: Use db update api once db supports it. + err = db.DBconn.Create(v.storeName, key, v.tagMeta, def) if err != nil { return pkgerrors.Wrap(err, "Storing updated chart metadata") } @@ -214,16 +236,17 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error { // Download the contents of the resource bundle definition from DB // Returns a byte array of the contents which is used by the // ExtractTarBall code to create the folder structure on disk -func (v *DefinitionClient) Download(id string) ([]byte, error) { +func (v *DefinitionClient) Download(name string, version string) ([]byte, error) { - key := definitionKey{Key: id} //ignore the returned data here //Check if id is valid - _, err := v.Get(id) + _, err := v.Get(name, version) if err != nil { return nil, pkgerrors.Errorf("Invalid Definition ID provided: %s", err.Error()) } + //Construct the composite key to select the entry + key := DefinitionKey{Name: name, Version: version} value, err := db.DBconn.Read(v.storeName, key, v.tagContent) if err != nil { return nil, pkgerrors.Wrap(err, "Get Resource Bundle definition content") diff --git a/src/k8splugin/internal/rb/definition_test.go b/src/k8splugin/internal/rb/definition_test.go index b1875fd7..96aaafbe 100644 --- a/src/k8splugin/internal/rb/definition_test.go +++ b/src/k8splugin/internal/rb/definition_test.go @@ -40,16 +40,16 @@ func TestCreateDefinition(t *testing.T) { { label: "Create Resource Bundle Definition", inp: Definition{ - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", Description: "testresourcebundle", - ServiceType: "firewall", + ChartName: "", }, expected: Definition{ - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", Description: "testresourcebundle", - ServiceType: "firewall", + ChartName: "", }, expectedError: "", mockdb: &db.MockDB{}, @@ -89,42 +89,44 @@ func TestListDefinition(t *testing.T) { testCases := []struct { label string + name string expectedError string mockdb *db.MockDB expected []Definition }{ { label: "List Resource Bundle Definition", + name: "testresourcebundle", expected: []Definition{ { - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", Description: "testresourcebundle", - ServiceType: "firewall", + ChartName: "testchart", }, { - UUID: "123e4567-e89b-12d3-a456-426655441111", - Name: "testresourcebundle2", - Description: "testresourcebundle2", - ServiceType: "dns", + Name: "testresourcebundle", + Version: "v2", + Description: "testresourcebundle_version2", + ChartName: "testchart", }, }, expectedError: "", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"testchart\"}"), }, - "123e4567-e89b-12d3-a456-426655441111": { + DefinitionKey{Name: "testresourcebundle", Version: "v2"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle2\"," + - "\"description\":\"testresourcebundle2\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," + - "\"service-type\":\"dns\"}"), + "{\"rb-name\":\"testresourcebundle\"," + + "\"description\":\"testresourcebundle_version2\"," + + "\"rb-version\":\"v2\"," + + "\"chart-name\":\"testchart\"}"), }, }, }, @@ -142,7 +144,7 @@ func TestListDefinition(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewDefinitionClient() - got, err := impl.List() + got, err := impl.List(testCase.name) if err != nil { if testCase.expectedError == "" { t.Fatalf("List returned an unexpected error %s", err) @@ -154,12 +156,12 @@ func TestListDefinition(t *testing.T) { // Since the order of returned slice is not guaranteed // Check both and return error if both don't match sort.Slice(got, func(i, j int) bool { - return got[i].UUID < got[j].UUID + return got[i].Version < got[j].Version }) // Sort both as it is not expected that testCase.expected // is sorted sort.Slice(testCase.expected, func(i, j int) bool { - return testCase.expected[i].UUID < testCase.expected[j].UUID + return testCase.expected[i].Version < testCase.expected[j].Version }) if reflect.DeepEqual(testCase.expected, got) == false { @@ -175,29 +177,32 @@ func TestGetDefinition(t *testing.T) { testCases := []struct { label string + name string + version string expectedError string mockdb *db.MockDB inp string expected Definition }{ { - label: "Get Resource Bundle Definition", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Get Resource Bundle Definition", + name: "testresourcebundle", + version: "v1", expected: Definition{ - UUID: "123e4567-e89b-12d3-a456-426655440000", Name: "testresourcebundle", + Version: "v1", Description: "testresourcebundle", - ServiceType: "firewall", + ChartName: "testchart", }, expectedError: "", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"testchart\"}"), }, }, }, @@ -215,7 +220,7 @@ func TestGetDefinition(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewDefinitionClient() - got, err := impl.Get(testCase.inp) + got, err := impl.Get(testCase.name, testCase.version) if err != nil { if testCase.expectedError == "" { t.Fatalf("Get returned an unexpected error %s", err) @@ -237,14 +242,16 @@ func TestDeleteDefinition(t *testing.T) { testCases := []struct { label string - inp string + name string + version string expectedError string mockdb *db.MockDB }{ { - label: "Delete Resource Bundle Definition", - inp: "123e4567-e89b-12d3-a456-426655440000", - mockdb: &db.MockDB{}, + label: "Delete Resource Bundle Definition", + name: "testresourcebundle", + version: "v1", + mockdb: &db.MockDB{}, }, { label: "Delete Error", @@ -259,7 +266,7 @@ func TestDeleteDefinition(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewDefinitionClient() - err := impl.Delete(testCase.inp) + err := impl.Delete(testCase.name, testCase.version) if err != nil { if testCase.expectedError == "" { t.Fatalf("Delete returned an unexpected error %s", err) @@ -275,14 +282,15 @@ func TestDeleteDefinition(t *testing.T) { func TestUploadDefinition(t *testing.T) { testCases := []struct { label string - inp string + name, version string content []byte expectedError string mockdb *db.MockDB }{ { - label: "Upload With Chart Name Detection", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Upload With Chart Name Detection", + name: "testresourcebundle", + version: "v1", //Binary format for testchart/Chart.yaml content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb3, 0xeb, 0x86, 0x5c, @@ -319,19 +327,19 @@ func TestUploadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"}"), }, }, }, }, { - label: "Upload With Chart Name", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Upload With Chart Name", + name: "testresourcebundle", + version: "v1", content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, @@ -355,20 +363,20 @@ func TestUploadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"chart-name\":\"testchart\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), }, }, }, }, { label: "Upload Without Chart.yaml", - inp: "123e4567-e89b-12d3-a456-426655440000", + name: "testresourcebundle", + version: "v1", expectedError: "Unable to detect chart name", content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, @@ -393,19 +401,20 @@ func TestUploadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), }, }, }, }, { label: "Upload with an Invalid Resource Bundle Definition", - inp: "123e4567-e89b-12d3-a456-426655440000", + name: "testresourcebundle", + version: "v1", expectedError: "Invalid Definition ID provided", content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, @@ -430,19 +439,20 @@ func TestUploadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655441111": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), }, }, }, }, { label: "Invalid File Format Error", - inp: "123e4567-e89b-12d3-a456-426655440000", + name: "testresourcebundle", + version: "v1", expectedError: "Error in file format", content: []byte{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -450,12 +460,12 @@ func TestUploadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), }, }, }, @@ -494,7 +504,7 @@ func TestUploadDefinition(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewDefinitionClient() - err := impl.Upload(testCase.inp, testCase.content) + err := impl.Upload(testCase.name, testCase.version, testCase.content) if err != nil { if testCase.expectedError == "" { t.Errorf("Upload returned an unexpected error %s", err) @@ -510,14 +520,15 @@ func TestUploadDefinition(t *testing.T) { func TestDownloadDefinition(t *testing.T) { testCases := []struct { label string - inp string + name, version string expected []byte expectedError string mockdb *db.MockDB }{ { - label: "Download Resource Bundle Definition", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Download Resource Bundle Definition", + name: "testresourcebundle", + version: "v1", expected: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, @@ -541,12 +552,12 @@ func TestDownloadDefinition(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), "content": []byte("H4sICLBr9FsAA3Rlc3QudGFyAO3OQQrCMBCF4aw9RU5" + "QEtLE40igAUtSC+2IHt9IEVwIpYtShP/bvGFmFk/SLI08Re3IVCG077Rn" + "b75zYZ2yztVV8N7XP9vWSWmzZ6mP+yxx0lrF7pJzjkN/Sz//1u5/6ppKG" + @@ -557,16 +568,17 @@ func TestDownloadDefinition(t *testing.T) { }, { label: "Download with an Invalid Resource Bundle Definition", - inp: "123e4567-e89b-12d3-a456-426655440000", + name: "testresourcebundle", + version: "v2", expectedError: "Invalid Definition ID provided", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655441111": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," + - "\"service-type\":\"firewall\"}"), + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"firewall\"}"), }, }, }, @@ -574,7 +586,6 @@ func TestDownloadDefinition(t *testing.T) { { label: "Download Error", expectedError: "DB Error", - inp: "123e4567-e89b-12d3-a456-426655440000", mockdb: &db.MockDB{ Err: pkgerrors.New("DB Error"), }, @@ -585,7 +596,7 @@ func TestDownloadDefinition(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewDefinitionClient() - data, err := impl.Download(testCase.inp) + data, err := impl.Download(testCase.name, testCase.version) if err != nil { if testCase.expectedError == "" { t.Errorf("Download returned an unexpected error %s", err) diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go index 006fa913..572a175c 100644 --- a/src/k8splugin/internal/rb/profile.go +++ b/src/k8splugin/internal/rb/profile.go @@ -19,11 +19,10 @@ package rb import ( "bytes" "encoding/base64" + "encoding/json" "k8splugin/internal/db" - "log" "path/filepath" - uuid "github.com/hashicorp/go-uuid" pkgerrors "github.com/pkg/errors" "k8splugin/internal/helm" @@ -32,29 +31,38 @@ import ( // Profile contains the parameters needed for resource bundle (rb) profiles // It implements the interface for managing the profiles type Profile struct { - UUID string `json:"uuid,omitempty"` - RBDID string `json:"rbdid"` - Name string `json:"name"` - Namespace string `json:"namespace"` - KubernetesVersion string `json:"kubernetesversion"` + RBName string `json:"rb-name"` + RBVersion string `json:"rb-version"` + Name string `json:"profile-name"` + ReleaseName string `json:"release-name"` + Namespace string `json:"namespace"` + KubernetesVersion string `json:"kubernetes-version"` + Labels map[string]string `json:"labels"` } // ProfileManager is an interface exposes the resource bundle profile functionality type ProfileManager interface { Create(def Profile) (Profile, error) - List() ([]Profile, error) - Get(resID string) (Profile, error) - Help() map[string]string - Delete(resID string) error - Upload(resID string, inp []byte) error + Get(rbName, rbVersion, prName string) (Profile, error) + Delete(rbName, rbVersion, prName string) error + Upload(rbName, rbVersion, prName string, inp []byte) error } -type profileKey struct { - Key string +type ProfileKey struct { + RBName string `json:"rb-name"` + RBVersion string `json:"rb-version"` + Name string `json:"profile-name"` } -func (dk profileKey) String() string { - return dk.Key +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (dk ProfileKey) String() string { + out, err := json.Marshal(dk) + if err != nil { + return "" + } + + return string(out) } // ProfileClient implements the ProfileManager @@ -67,80 +75,61 @@ type ProfileClient struct { // NewProfileClient returns an instance of the ProfileClient // which implements the ProfileManager -// Uses rb/def prefix func NewProfileClient() *ProfileClient { return &ProfileClient{ - storeName: "rbprofile", + storeName: "rbdef", tagMeta: "metadata", tagContent: "content", manifestName: "manifest.yaml", } } -// Help returns some information on how to create the content -// for the profile in the form of html formatted page -func (v *ProfileClient) Help() map[string]string { - ret := make(map[string]string) - - return ret -} - // Create an entry for the resource bundle profile in the database func (v *ProfileClient) Create(p Profile) (Profile, error) { - //Check if provided RBID is a valid resource bundle - _, err := NewDefinitionClient().Get(p.RBDID) - if err != nil { - return Profile{}, pkgerrors.Errorf("Invalid Resource Bundle ID provided: %s", err.Error()) - } - // Name is required if p.Name == "" { return Profile{}, pkgerrors.New("Name is required for Resource Bundle Profile") } - // If UUID is empty, we will generate one - if p.UUID == "" { - p.UUID, _ = uuid.GenerateUUID() + //Check if profile already exists + _, err := v.Get(p.RBName, p.RBVersion, p.Name) + if err == nil { + return Profile{}, pkgerrors.New("Profile already exists for this Definition") } - key := profileKey{Key: p.UUID} - err = db.DBconn.Create(v.storeName, key, v.tagMeta, p) + //Check if provided resource bundle information is valid + _, err = NewDefinitionClient().Get(p.RBName, p.RBVersion) if err != nil { - return Profile{}, pkgerrors.Wrap(err, "Creating Profile DB Entry") + return Profile{}, pkgerrors.Errorf("Invalid Resource Bundle ID provided: %s", err.Error()) } - return p, nil -} + //If release-name is not provided, we store name instead + if p.ReleaseName == "" { + p.ReleaseName = p.Name + } -// List all resource entries in the database -func (v *ProfileClient) List() ([]Profile, error) { - res, err := db.DBconn.ReadAll(v.storeName, v.tagMeta) - if err != nil || len(res) == 0 { - return []Profile{}, pkgerrors.Wrap(err, "Listing Resource Bundle Profiles") + key := ProfileKey{ + RBName: p.RBName, + RBVersion: p.RBVersion, + Name: p.Name, } - var retData []Profile - - for key, value := range res { - //value is a byte array - if len(value) > 0 { - pr := Profile{} - err = db.DBconn.Unmarshal(value, &pr) - if err != nil { - log.Printf("[Profile] Error Unmarshaling value for: %s", key) - continue - } - retData = append(retData, pr) - } + err = db.DBconn.Create(v.storeName, key, v.tagMeta, p) + if err != nil { + return Profile{}, pkgerrors.Wrap(err, "Creating Profile DB Entry") } - return retData, nil + return p, nil } // Get returns the Resource Bundle Profile for corresponding ID -func (v *ProfileClient) Get(id string) (Profile, error) { - key := profileKey{Key: id} +func (v *ProfileClient) Get(rbName, rbVersion, prName string) (Profile, error) { + key := ProfileKey{ + RBName: rbName, + RBVersion: rbVersion, + Name: prName, + } value, err := db.DBconn.Read(v.storeName, key, v.tagMeta) if err != nil { return Profile{}, pkgerrors.Wrap(err, "Get Resource Bundle Profile") @@ -160,8 +149,12 @@ func (v *ProfileClient) Get(id string) (Profile, error) { } // Delete the Resource Bundle Profile from database -func (v *ProfileClient) Delete(id string) error { - key := profileKey{Key: id} +func (v *ProfileClient) Delete(rbName, rbVersion, prName string) error { + key := ProfileKey{ + RBName: rbName, + RBVersion: rbVersion, + Name: prName, + } err := db.DBconn.Delete(v.storeName, key, v.tagMeta) if err != nil { return pkgerrors.Wrap(err, "Delete Resource Bundle Profile") @@ -176,13 +169,12 @@ func (v *ProfileClient) Delete(id string) error { } // Upload the contents of resource bundle into database -func (v *ProfileClient) Upload(id string, inp []byte) error { +func (v *ProfileClient) Upload(rbName, rbVersion, prName string, inp []byte) error { - key := profileKey{Key: id} //ignore the returned data here. - _, err := v.Get(id) + _, err := v.Get(rbName, rbVersion, prName) if err != nil { - return pkgerrors.Errorf("Invalid Profile ID provided %s", err.Error()) + return pkgerrors.Errorf("Invalid Profile Name provided %s", err.Error()) } err = isTarGz(bytes.NewBuffer(inp)) @@ -190,6 +182,11 @@ func (v *ProfileClient) Upload(id string, inp []byte) error { return pkgerrors.Errorf("Error in file format %s", err.Error()) } + key := ProfileKey{ + RBName: rbName, + RBVersion: rbVersion, + Name: prName, + } //Encode given byte stream to text for storage encodedStr := base64.StdEncoding.EncodeToString(inp) err = db.DBconn.Create(v.storeName, key, v.tagContent, encodedStr) @@ -203,16 +200,20 @@ func (v *ProfileClient) Upload(id string, inp []byte) error { // Download the contents of the resource bundle profile from DB // Returns a byte array of the contents which is used by the // ExtractTarBall code to create the folder structure on disk -func (v *ProfileClient) Download(id string) ([]byte, error) { +func (v *ProfileClient) Download(rbName, rbVersion, prName string) ([]byte, error) { - key := profileKey{Key: id} //ignore the returned data here //Check if id is valid - _, err := v.Get(id) + _, err := v.Get(rbName, rbVersion, prName) if err != nil { - return nil, pkgerrors.Errorf("Invalid Profile ID provided: %s", err.Error()) + return nil, pkgerrors.Errorf("Invalid Profile Name provided: %s", err.Error()) } + key := ProfileKey{ + RBName: rbName, + RBVersion: rbVersion, + Name: prName, + } value, err := db.DBconn.Read(v.storeName, key, v.tagContent) if err != nil { return nil, pkgerrors.Wrap(err, "Get Resource Bundle Profile content") @@ -234,13 +235,14 @@ func (v *ProfileClient) Download(id string) ([]byte, error) { //Resolve returns the path where the helm chart merged with //configuration overrides resides. -func (v *ProfileClient) Resolve(id string, values []string) (map[string][]string, error) { +func (v *ProfileClient) Resolve(rbName string, rbVersion string, + profileName string, values []string) (map[string][]string, error) { var retMap map[string][]string //Download and process the profile first //If everything seems okay, then download the definition - prData, err := v.Download(id) + prData, err := v.Download(rbName, rbVersion, profileName) if err != nil { return retMap, pkgerrors.Wrap(err, "Downloading Profile") } @@ -255,20 +257,14 @@ func (v *ProfileClient) Resolve(id string, values []string) (map[string][]string return retMap, pkgerrors.Wrap(err, "Processing Profile Manifest") } - //Get the definition ID and download its contents - profile, err := v.Get(id) - if err != nil { - return retMap, pkgerrors.Wrap(err, "Getting Profile") - } - definitionClient := NewDefinitionClient() - definition, err := definitionClient.Get(profile.RBDID) + definition, err := definitionClient.Get(rbName, rbVersion) if err != nil { return retMap, pkgerrors.Wrap(err, "Getting Definition Metadata") } - defData, err := definitionClient.Download(profile.RBDID) + defData, err := definitionClient.Download(rbName, rbVersion) if err != nil { return retMap, pkgerrors.Wrap(err, "Downloading Definition") } @@ -278,6 +274,12 @@ func (v *ProfileClient) Resolve(id string, values []string) (map[string][]string return retMap, pkgerrors.Wrap(err, "Extracting Definition Charts") } + //Get the definition ID and download its contents + profile, err := v.Get(rbName, rbVersion, profileName) + if err != nil { + return retMap, pkgerrors.Wrap(err, "Getting Profile") + } + //Copy the profile configresources to the chart locations //Corresponds to the following from the profile yaml // configresource: @@ -290,7 +292,7 @@ func (v *ProfileClient) Resolve(id string, values []string) (map[string][]string helmClient := helm.NewTemplateClient(profile.KubernetesVersion, profile.Namespace, - profile.Name) + profile.ReleaseName) chartPath := filepath.Join(chartBasePath, definition.ChartName) retMap, err = helmClient.GenerateKubernetesArtifacts(chartPath, diff --git a/src/k8splugin/internal/rb/profile_test.go b/src/k8splugin/internal/rb/profile_test.go index df0db18a..5d41b019 100644 --- a/src/k8splugin/internal/rb/profile_test.go +++ b/src/k8splugin/internal/rb/profile_test.go @@ -22,7 +22,6 @@ import ( "bytes" "k8splugin/internal/db" "reflect" - "sort" "strings" "testing" @@ -40,101 +39,62 @@ func TestCreateProfile(t *testing.T) { { label: "Create Resource Bundle Profile", inp: Profile{ - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", + Name: "testprofile1", + ReleaseName: "testprofilereleasename", + Namespace: "testnamespace", KubernetesVersion: "1.12.3", + RBName: "testresourcebundle", + RBVersion: "v1", }, expected: Profile{ - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", + Name: "testprofile1", + ReleaseName: "testprofilereleasename", + Namespace: "testnamespace", KubernetesVersion: "1.12.3", + RBName: "testresourcebundle", + RBVersion: "v1", }, expectedError: "", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "abcde123-e89b-8888-a456-986655447236": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"kubernetesversion\":\"1.12.3\"}"), + "{\"rb-name\":\"testresourcebundle\"," + + "\"description\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"testchart\"}"), }, }, }, }, { - label: "Failed Create Resource Bundle Profile", - expectedError: "Error Creating Profile", - mockdb: &db.MockDB{ - Err: pkgerrors.New("Error Creating Profile"), - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - db.DBconn = testCase.mockdb - impl := NewProfileClient() - got, err := impl.Create(testCase.inp) - if err != nil { - if testCase.expectedError == "" { - t.Fatalf("Create returned an unexpected error %s", err) - } - if strings.Contains(err.Error(), testCase.expectedError) == false { - t.Fatalf("Create returned an unexpected error %s", err) - } - } else { - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ - " expected %v", got, testCase.expected) - } - } - }) - } -} - -func TestListProfiles(t *testing.T) { - - testCases := []struct { - label string - expectedError string - mockdb *db.MockDB - expected []Profile - }{ - { - label: "List Resource Bundle Profile", - expected: []Profile{ - { - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", - KubernetesVersion: "1.12.3", - }, + label: "Create Resource Bundle Profile With Non-Existing Definition", + inp: Profile{ + Name: "testprofile1", + ReleaseName: "testprofilereleasename", + Namespace: "testnamespace", + KubernetesVersion: "1.12.3", + RBName: "testresourcebundle", + RBVersion: "v1", }, - expectedError: "", + expectedError: "Error getting Resource Bundle Definition", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + DefinitionKey{Name: "testresourcebundle", Version: "v2"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + - "\"kubernetesversion\":\"1.12.3\"}"), + "{\"rb-name\":\"testresourcebundle\"," + + "\"description\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + + "\"chart-name\":\"testchart\"}"), }, }, }, }, { - label: "List Error", - expectedError: "DB Error", + label: "Failed Create Resource Bundle Profile", + expectedError: "Name is required", mockdb: &db.MockDB{ - Err: pkgerrors.New("DB Error"), + Err: pkgerrors.New("Error Creating Profile"), }, }, } @@ -143,28 +103,17 @@ func TestListProfiles(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - got, err := impl.List() + got, err := impl.Create(testCase.inp) if err != nil { if testCase.expectedError == "" { - t.Fatalf("List returned an unexpected error %s", err) + t.Fatalf("Create returned an unexpected error %s", err) } if strings.Contains(err.Error(), testCase.expectedError) == false { - t.Fatalf("List returned an unexpected error %s", err) + t.Fatalf("Create returned an unexpected error %s", err) } } else { - // Since the order of returned slice is not guaranteed - // Check both and return error if both don't match - sort.Slice(got, func(i, j int) bool { - return got[i].UUID < got[j].UUID - }) - // Sort both as it is not expected that testCase.expected - // is sorted - sort.Slice(testCase.expected, func(i, j int) bool { - return testCase.expected[i].UUID < testCase.expected[j].UUID - }) - if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("List Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ " expected %v", got, testCase.expected) } } @@ -175,32 +124,36 @@ func TestListProfiles(t *testing.T) { func TestGetProfile(t *testing.T) { testCases := []struct { - label string - expectedError string - mockdb *db.MockDB - inp string - expected Profile + label string + rbname, rbversion, prname string + expectedError string + mockdb *db.MockDB + expected Profile }{ { - label: "Get Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Get Resource Bundle Profile", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", expected: Profile{ - UUID: "123e4567-e89b-12d3-a456-426655440000", - RBDID: "abcde123-e89b-8888-a456-986655447236", - Name: "testresourcebundle", - Namespace: "default", + Name: "testprofile1", + ReleaseName: "testprofilereleasename", + Namespace: "testnamespace", KubernetesVersion: "1.12.3", + RBName: "testresourcebundle", + RBVersion: "v1", }, expectedError: "", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + - "\"kubernetesversion\":\"1.12.3\"}"), + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + + "\"kubernetes-version\":\"1.12.3\"}"), }, }, }, @@ -218,7 +171,7 @@ func TestGetProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - got, err := impl.Get(testCase.inp) + got, err := impl.Get(testCase.rbname, testCase.rbversion, testCase.prname) if err != nil { if testCase.expectedError == "" { t.Fatalf("Get returned an unexpected error %s", err) @@ -239,15 +192,17 @@ func TestGetProfile(t *testing.T) { func TestDeleteProfile(t *testing.T) { testCases := []struct { - label string - inp string - expectedError string - mockdb *db.MockDB + label string + rbname, rbversion, prname string + expectedError string + mockdb *db.MockDB }{ { - label: "Delete Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", - mockdb: &db.MockDB{}, + label: "Delete Resource Bundle Profile", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", + mockdb: &db.MockDB{}, }, { label: "Delete Error", @@ -262,7 +217,7 @@ func TestDeleteProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - err := impl.Delete(testCase.inp) + err := impl.Delete(testCase.rbname, testCase.rbversion, testCase.prname) if err != nil { if testCase.expectedError == "" { t.Fatalf("Delete returned an unexpected error %s", err) @@ -277,15 +232,17 @@ func TestDeleteProfile(t *testing.T) { func TestUploadProfile(t *testing.T) { testCases := []struct { - label string - inp string - content []byte - expectedError string - mockdb *db.MockDB + label string + rbname, rbversion, prname string + content []byte + expectedError string + mockdb *db.MockDB }{ { - label: "Upload Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Upload Resource Bundle Profile", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, @@ -309,12 +266,13 @@ func TestUploadProfile(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"kubernetesversion\":\"1.12.3\"}"), }, }, @@ -322,8 +280,10 @@ func TestUploadProfile(t *testing.T) { }, { label: "Upload with an Invalid Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", - expectedError: "Invalid Profile ID provided", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", + expectedError: "Invalid Profile Name provided", content: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, @@ -347,12 +307,13 @@ func TestUploadProfile(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655441111": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile2"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"kubernetesversion\":\"1.12.3\"}"), }, }, @@ -360,7 +321,9 @@ func TestUploadProfile(t *testing.T) { }, { label: "Invalid File Format Error", - inp: "123e4567-e89b-12d3-a456-426655440000", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", expectedError: "Error in file format", content: []byte{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -368,12 +331,13 @@ func TestUploadProfile(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"kubernetesversion\":\"1.12.3\"}"), }, }, @@ -413,7 +377,7 @@ func TestUploadProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - err := impl.Upload(testCase.inp, testCase.content) + err := impl.Upload(testCase.rbname, testCase.rbversion, testCase.prname, testCase.content) if err != nil { if testCase.expectedError == "" { t.Errorf("Upload returned an unexpected error %s", err) @@ -428,15 +392,17 @@ func TestUploadProfile(t *testing.T) { func TestDownloadProfile(t *testing.T) { testCases := []struct { - label string - inp string - expected []byte - expectedError string - mockdb *db.MockDB + label string + rbname, rbversion, prname string + expected []byte + expectedError string + mockdb *db.MockDB }{ { - label: "Download Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", + label: "Download Resource Bundle Profile", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", expected: []byte{ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, @@ -460,12 +426,13 @@ func TestDownloadProfile(t *testing.T) { }, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"kubernetesversion\":\"1.12.3\"}"), "content": []byte("H4sICLBr9FsAA3Rlc3QudGFyAO3OQQrCMBCF4aw9RU5" + "QEtLE40igAUtSC+2IHt9IEVwIpYtShP/bvGFmFk/SLI08Re3IVCG077Rn" + @@ -477,16 +444,19 @@ func TestDownloadProfile(t *testing.T) { }, { label: "Download with an Invalid Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", - expectedError: "Invalid Profile ID provided", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", + expectedError: "Invalid Profile Name provided", mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655441111": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", Name: "testprofile2"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," + - "\"namespace\":\"default\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"profile-name\":\"testprofile1\"," + + "\"release-name\":\"testprofilereleasename\"," + + "\"namespace\":\"testnamespace\"," + + "\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"kubernetesversion\":\"1.12.3\"}"), }, }, @@ -495,7 +465,9 @@ func TestDownloadProfile(t *testing.T) { { label: "Download Error", expectedError: "DB Error", - inp: "123e4567-e89b-12d3-a456-426655440000", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "testprofile1", mockdb: &db.MockDB{ Err: pkgerrors.New("DB Error"), }, @@ -506,7 +478,7 @@ func TestDownloadProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - data, err := impl.Download(testCase.inp) + data, err := impl.Download(testCase.rbname, testCase.rbversion, testCase.prname) if err != nil { if testCase.expectedError == "" { t.Errorf("Download returned an unexpected error %s", err) @@ -526,24 +498,28 @@ func TestDownloadProfile(t *testing.T) { func TestResolveProfile(t *testing.T) { testCases := []struct { - label string - inp string - expected map[string][]string - expectedError string - mockdb *db.MockDB + label string + rbname, rbversion, prname string + expected map[string][]string + expectedError string + mockdb *db.MockDB }{ { - label: "Resolve Resource Bundle Profile", - inp: "123e4567-e89b-12d3-a456-426655440000", - expected: map[string][]string{}, + label: "Resolve Resource Bundle Profile", + rbname: "testresourcebundle", + rbversion: "v1", + prname: "profile1", + expected: map[string][]string{}, mockdb: &db.MockDB{ Items: map[string]map[string][]byte{ - "123e4567-e89b-12d3-a456-426655440000": { + ProfileKey{RBName: "testresourcebundle", RBVersion: "v1", + Name: "profile1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + - "\"namespace\":\"default\"," + - "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," + - "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," + + "{\"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" + @@ -570,13 +546,12 @@ func TestResolveProfile(t *testing.T) { "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" + "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA="), }, - "abcde123-e89b-8888-a456-986655447236": { + DefinitionKey{Name: "testresourcebundle", Version: "v1"}.String(): { "metadata": []byte( - "{\"name\":\"testresourcebundle\"," + + "{\"rb-name\":\"testresourcebundle\"," + + "\"rb-version\":\"v1\"," + "\"chart-name\":\"vault-consul-dev\"," + - "\"description\":\"testresourcebundle\"," + - "\"uuid\":\"abcde123-e89b-8888-a456-986655447236\"," + - "\"service-type\":\"firewall\"}"), + "\"description\":\"testresourcebundle\"}"), // base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev "content": []byte("H4sICEetS1wAA3ZhdWx0LWNvbnN1bC1kZXYudGFyAO0c7XLbNjK/+R" + "QYujdJehatb+V4czPnOmnPk9bO2Gk7nbaTgUhIxpgiGAK0o3P9QPca92S3C5AU9GXZiax" + @@ -651,7 +626,8 @@ func TestResolveProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - data, err := impl.Resolve(testCase.inp, []string{}) + data, err := impl.Resolve(testCase.rbname, testCase.rbversion, testCase.prname, + []string{}) if err != nil { if testCase.expectedError == "" { t.Errorf("Resolve returned an unexpected error %s", err) diff --git a/src/k8splugin/mock_files/mock_json/create_rbdefinition.json b/src/k8splugin/mock_files/mock_json/create_rbdefinition.json index 370c3c79..0373113c 100644 --- a/src/k8splugin/mock_files/mock_json/create_rbdefinition.json +++ b/src/k8splugin/mock_files/mock_json/create_rbdefinition.json @@ -1,7 +1,9 @@ { - "uuid": "7eb09e38-4363-9942-1234-3beb2e95fd85", - "name": "test-rbdef", + "rb-name": "test-rbdef", + "rb-version": "v1", "chart-name": "testchart", "description": "testing resource bundle definition api", - "service-type": "firewall" + "labels": { + "vnf_customization_module_uuid": "7eb09e38-4363-9942-1234-3beb2e95fd85" + } } \ No newline at end of file diff --git a/src/k8splugin/mock_files/mock_json/create_rbprofile.json b/src/k8splugin/mock_files/mock_json/create_rbprofile.json index 5d439cf0..72111a4d 100644 --- a/src/k8splugin/mock_files/mock_json/create_rbprofile.json +++ b/src/k8splugin/mock_files/mock_json/create_rbprofile.json @@ -1,7 +1,11 @@ { - "name": "test-rbprofile", - "description": "testing resource bundle profile api", - "rbdid": "7eb09e38-4363-9942-1234-3beb2e95fd85", - "uuid": "12345678-8888-4578-3344-987654398731", - "service-type": "firewall" + "rb-name": "test-rbdef", + "rb-version": "v1", + "profile-name": "profile1", + "release-name": "testrelease", + "namespace": "testnamespace", + "kubernetes-version": "1.12.3", + "labels": { + "vnf_customization_module_uuid": "7eb09e38-4363-9942-1234-3beb2e95fd85" + } } -- cgit 1.2.3-korg