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 --- 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 +++++++++++++-------------- 9 files changed, 435 insertions(+), 420 deletions(-) (limited to 'src/k8splugin/internal') 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) -- cgit 1.2.3-korg