diff options
Diffstat (limited to 'src/orchestrator/pkg')
-rw-r--r-- | src/orchestrator/pkg/module/add_intents.go | 184 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/deployment_intent_groups.go | 177 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/deployment_intent_groups_test.go | 230 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/generic_placement_intent.go | 12 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/generic_placement_intent_test.go | 12 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/module.go | 15 |
6 files changed, 612 insertions, 18 deletions
diff --git a/src/orchestrator/pkg/module/add_intents.go b/src/orchestrator/pkg/module/add_intents.go new file mode 100644 index 00000000..a657cce7 --- /dev/null +++ b/src/orchestrator/pkg/module/add_intents.go @@ -0,0 +1,184 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by Addlicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "encoding/json" + "reflect" + + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// Intent shall have 2 fields - MetaData and Spec +type Intent struct { + MetaData IntentMetaData `json:"metadata"` + Spec IntentSpecData `json:"spec"` +} + +// IntentMetaData has Name, Description, userdata1, userdata2 +type IntentMetaData struct { + Name string `json:"name"` + Description string `json:"description"` + UserData1 string `json:"userData1"` + UserData2 string `json:"userData2"` +} + +// IntentSpecData has Intent +type IntentSpecData struct { + Intent IntentObj `json:"intent"` +} + +// IntentObj has name of the generic placement intent +type IntentObj struct { + Generic string `json:"generic"` +} + +// ListOfIntents is a list of intents +type ListOfIntents struct { + ListOfIntents []map[string]string `json:"intent"` +} + +// IntentManager is an interface which exposes the IntentManager functionality +type IntentManager interface { + AddIntent(a Intent, p string, ca string, v string, di string) (Intent, error) + GetIntent(i string, p string, ca string, v string, di string) (Intent, error) + DeleteIntent(i string, p string, ca string, v string, di string) error +} + +// IntentKey consists of Name if the intent, Project name, CompositeApp name, +// CompositeApp version +type IntentKey struct { + Name string `json:"name"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + Version string `json:"version"` + DeploymentIntentGroup string `json:"deployment-intent-group-name"` +} + +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (ik IntentKey) String() string { + out, err := json.Marshal(ik) + if err != nil { + return "" + } + return string(out) +} + +// IntentClient implements the AddIntentManager interface +type IntentClient struct { + storeName string + tagMetaData string +} + +// NewIntentClient returns an instance of AddIntentClient +func NewIntentClient() *IntentClient { + return &IntentClient{ + storeName: "orchestrator", + tagMetaData: "addintent", + } +} + +// AddIntent adds a given intent to the deployment-intent-group and stores in the db. Other input parameters for it - projectName, compositeAppName, version, DeploymentIntentgroupName +func (c *IntentClient) AddIntent(a Intent, p string, ca string, v string, di string) (Intent, error) { + + //Check for the AddIntent already exists here. + res, err := c.GetIntent(a.MetaData.Name, p, ca, v, di) + if !reflect.DeepEqual(res, Intent{}) { + return Intent{}, pkgerrors.New("AppIntent already exists") + } + + //Check if project exists + _, err = NewProjectClient().GetProject(p) + if err != nil { + return Intent{}, pkgerrors.New("Unable to find the project") + } + + //check if compositeApp exists + _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p) + if err != nil { + return Intent{}, pkgerrors.New("Unable to find the composite-app") + } + + //check if DeploymentIntentGroup exists + _, err = NewDeploymentIntentGroupClient().GetDeploymentIntentGroup(di, p, ca, v) + if err != nil { + return Intent{}, pkgerrors.New("Unable to find the intent") + } + + akey := IntentKey{ + Name: a.MetaData.Name, + Project: p, + CompositeApp: ca, + Version: v, + DeploymentIntentGroup: di, + } + + err = db.DBconn.Insert(c.storeName, akey, nil, c.tagMetaData, a) + if err != nil { + return Intent{}, pkgerrors.Wrap(err, "Create DB entry error") + } + return a, nil +} + +// GetIntent returns an Intent +func (c *IntentClient) GetIntent(i string, p string, ca string, v string, di string) (Intent, error) { + + k := IntentKey{ + Name: i, + Project: p, + CompositeApp: ca, + Version: v, + DeploymentIntentGroup: di, + } + + result, err := db.DBconn.Find(c.storeName, k, c.tagMetaData) + if err != nil { + return Intent{}, pkgerrors.Wrap(err, "Get AppIntent error") + } + + if result != nil { + a := Intent{} + err = db.DBconn.Unmarshal(result[0], &a) + if err != nil { + return Intent{}, pkgerrors.Wrap(err, "Unmarshalling AppIntent") + } + return a, nil + + } + return Intent{}, pkgerrors.New("Error getting AppIntent") +} + +// DeleteIntent deletes a given intent tied to project, composite app and deployment intent group +func (c IntentClient) DeleteIntent(i string, p string, ca string, v string, di string) error { + k := IntentKey{ + Name: i, + Project: p, + CompositeApp: ca, + Version: v, + DeploymentIntentGroup: di, + } + + err := db.DBconn.Remove(c.storeName, k) + if err != nil { + return pkgerrors.Wrap(err, "Delete Project entry;") + } + return nil + +} diff --git a/src/orchestrator/pkg/module/deployment_intent_groups.go b/src/orchestrator/pkg/module/deployment_intent_groups.go new file mode 100644 index 00000000..fe622771 --- /dev/null +++ b/src/orchestrator/pkg/module/deployment_intent_groups.go @@ -0,0 +1,177 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "encoding/json" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + "reflect" + + pkgerrors "github.com/pkg/errors" +) + +// DeploymentIntentGroup shall have 2 fields - MetaData and Spec +type DeploymentIntentGroup struct { + MetaData DepMetaData `json:"metadata"` + Spec DepSpecData `json:"spec"` +} + +// DepMetaData has Name, description, userdata1, userdata2 +type DepMetaData struct { + Name string `json:"name"` + Description string `json:"description"` + UserData1 string `json:"userData1"` + UserData2 string `json:"userData2"` +} + +// DepSpecData has profile, version, OverrideValuesObj +type DepSpecData struct { + Profile string `json:"profile"` + Version string `json:"version"` + OverrideValuesObj []OverrideValues `json:"override-values"` +} + +// OverrideValues has appName and ValuesObj +type OverrideValues struct { + AppName string `json:"app-name"` + ValuesObj map[string]string `json:"values"` +} + +// Values has ImageRepository +// type Values struct { +// ImageRepository string `json:"imageRepository"` +// } + +// DeploymentIntentGroupManager is an interface which exposes the DeploymentIntentGroupManager functionality +type DeploymentIntentGroupManager interface { + CreateDeploymentIntentGroup(d DeploymentIntentGroup, p string, ca string, v string) (DeploymentIntentGroup, error) + GetDeploymentIntentGroup(di string, p string, ca string, v string) (DeploymentIntentGroup, error) + DeleteDeploymentIntentGroup(di string, p string, ca string, v string) error +} + +// DeploymentIntentGroupKey consists of Name of the deployment group, project name, CompositeApp name, CompositeApp version +type DeploymentIntentGroupKey struct { + Name string `json:"name"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + Version string `json:"version"` +} + +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (dk DeploymentIntentGroupKey) String() string { + out, err := json.Marshal(dk) + if err != nil { + return "" + } + return string(out) +} + +// DeploymentIntentGroupClient implements the DeploymentIntentGroupManager interface +type DeploymentIntentGroupClient struct { + storeName string + tagMetaData string +} + +// NewDeploymentIntentGroupClient return an instance of DeploymentIntentGroupClient which implements DeploymentIntentGroupManager +func NewDeploymentIntentGroupClient() *DeploymentIntentGroupClient { + return &DeploymentIntentGroupClient{ + storeName: "orchestrator", + tagMetaData: "deploymentintentgroup", + } +} + +// CreateDeploymentIntentGroup creates an entry for a given DeploymentIntentGroup in the database. Other Input parameters for it - projectName, compositeAppName, version +func (c *DeploymentIntentGroupClient) CreateDeploymentIntentGroup(d DeploymentIntentGroup, p string, ca string, + v string) (DeploymentIntentGroup, error) { + + res, err := c.GetDeploymentIntentGroup(d.MetaData.Name, p, ca, v) + if !reflect.DeepEqual(res, DeploymentIntentGroup{}) { + return DeploymentIntentGroup{}, pkgerrors.New("AppIntent already exists") + } + + //Check if project exists + _, err = NewProjectClient().GetProject(p) + if err != nil { + return DeploymentIntentGroup{}, pkgerrors.New("Unable to find the project") + } + + //check if compositeApp exists + _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p) + if err != nil { + return DeploymentIntentGroup{}, pkgerrors.New("Unable to find the composite-app") + } + + gkey := DeploymentIntentGroupKey{ + Name: d.MetaData.Name, + Project: p, + CompositeApp: ca, + Version: v, + } + + err = db.DBconn.Insert(c.storeName, gkey, nil, c.tagMetaData, d) + if err != nil { + return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Create DB entry error") + } + + return d, nil +} + +// GetDeploymentIntentGroup returns the DeploymentIntentGroup with a given name, project, compositeApp and version of compositeApp +func (c *DeploymentIntentGroupClient) GetDeploymentIntentGroup(di string, p string, ca string, v string) (DeploymentIntentGroup, error) { + + key := DeploymentIntentGroupKey{ + Name: di, + Project: p, + CompositeApp: ca, + Version: v, + } + + result, err := db.DBconn.Find(c.storeName, key, c.tagMetaData) + if err != nil { + return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Get DeploymentIntentGroup error") + } + + if result != nil { + d := DeploymentIntentGroup{} + err = db.DBconn.Unmarshal(result[0], &d) + if err != nil { + return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Unmarshalling DeploymentIntentGroup") + } + return d, nil + } + + return DeploymentIntentGroup{}, pkgerrors.New("Error getting DeploymentIntentGroup") + +} + +// DeleteDeploymentIntentGroup deletes a DeploymentIntentGroup +func (c *DeploymentIntentGroupClient) DeleteDeploymentIntentGroup(di string, p string, ca string, v string) error { + k := DeploymentIntentGroupKey{ + Name: di, + Project: p, + CompositeApp: ca, + Version: v, + } + + err := db.DBconn.Remove(c.storeName, k) + if err != nil { + return pkgerrors.Wrap(err, "Delete DeploymentIntentGroup entry;") + } + return nil + +} diff --git a/src/orchestrator/pkg/module/deployment_intent_groups_test.go b/src/orchestrator/pkg/module/deployment_intent_groups_test.go new file mode 100644 index 00000000..c0876ceb --- /dev/null +++ b/src/orchestrator/pkg/module/deployment_intent_groups_test.go @@ -0,0 +1,230 @@ +/* + * Copyright 2020 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package module + +import ( + "reflect" + "strings" + "testing" + + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" +) + +func TestCreateDeploymentIntentGroup(t *testing.T) { + testCases := []struct { + label string + inputDeploymentIntentGrp DeploymentIntentGroup + inputProject string + inputCompositeApp string + inputCompositeAppVersion string + expectedError string + mockdb *db.MockDB + expected DeploymentIntentGroup + }{ + { + label: "Create DeploymentIntentGroup", + inputDeploymentIntentGrp: DeploymentIntentGroup{ + MetaData: DepMetaData{ + Name: "testDeploymentIntentGroup", + Description: "DescriptionTestDeploymentIntentGroup", + UserData1: "userData1", + UserData2: "userData2", + }, + Spec: DepSpecData{ + Profile: "Testprofile", + Version: "version of deployment", + OverrideValuesObj: []OverrideValues{ + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + }, + }, + }, + inputProject: "testProject", + inputCompositeApp: "testCompositeApp", + inputCompositeAppVersion: "testCompositeAppVersion", + expected: DeploymentIntentGroup{ + MetaData: DepMetaData{ + Name: "testDeploymentIntentGroup", + Description: "DescriptionTestDeploymentIntentGroup", + UserData1: "userData1", + UserData2: "userData2", + }, + Spec: DepSpecData{ + Profile: "Testprofile", + Version: "version of deployment", + OverrideValuesObj: []OverrideValues{ + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + }, + }, + }, + expectedError: "", + mockdb: &db.MockDB{ + Items: map[string]map[string][]byte{ + ProjectKey{ProjectName: "testProject"}.String(): { + "projectmetadata": []byte( + "{\"project-name\":\"testProject\"," + + "\"description\":\"Test project for unit testing\"}"), + }, + CompositeAppKey{CompositeAppName: "testCompositeApp", + Version: "testCompositeAppVersion", Project: "testProject"}.String(): { + "compositeAppmetadata": []byte( + "{\"metadata\":{" + + "\"name\":\"testCompositeApp\"," + + "\"description\":\"description\"," + + "\"userData1\":\"user data\"," + + "\"userData2\":\"user data\"" + + "}," + + "\"spec\":{" + + "\"version\":\"version of the composite app\"}}"), + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + db.DBconn = testCase.mockdb + depIntentCli := NewDeploymentIntentGroupClient() + got, err := depIntentCli.CreateDeploymentIntentGroup(testCase.inputDeploymentIntentGrp, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("CreateDeploymentIntentGroup returned an unexpected error %s, ", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("CreateDeploymentIntentGroup returned an unexpected error %s", err) + } + } else { + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("CreateDeploymentIntentGroup returned unexpected body: got %v; "+" expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestGetDeploymentIntentGroup(t *testing.T) { + testCases := []struct { + label string + inputDeploymentIntentGrp string + inputProject string + inputCompositeApp string + inputCompositeAppVersion string + expected DeploymentIntentGroup + expectedError string + mockdb *db.MockDB + }{ + { + label: "Get DeploymentIntentGroup", + inputDeploymentIntentGrp: "testDeploymentIntentGroup", + inputProject: "testProject", + inputCompositeApp: "testCompositeApp", + inputCompositeAppVersion: "testCompositeAppVersion", + expected: DeploymentIntentGroup{ + MetaData: DepMetaData{ + Name: "testDeploymentIntentGroup", + Description: "DescriptionTestDeploymentIntentGroup", + UserData1: "userData1", + UserData2: "userData2", + }, + Spec: DepSpecData{ + Profile: "Testprofile", + Version: "version of deployment", + OverrideValuesObj: []OverrideValues{ + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + {AppName: "TestAppName", + ValuesObj: map[string]string{ + "imageRepository": "registry.hub.docker.com", + }}, + }, + }, + }, + expectedError: "", + mockdb: &db.MockDB{ + Items: map[string]map[string][]byte{ + DeploymentIntentGroupKey{ + Name: "testDeploymentIntentGroup", + Project: "testProject", + CompositeApp: "testCompositeApp", + Version: "testCompositeAppVersion", + }.String(): { + "deploymentintentgroup": []byte( + "{\"metadata\":{\"name\":\"testDeploymentIntentGroup\"," + + "\"description\":\"DescriptionTestDeploymentIntentGroup\"," + + "\"userData1\": \"userData1\"," + + "\"userData2\": \"userData2\"}," + + "\"spec\":{\"profile\": \"Testprofile\"," + + "\"version\": \"version of deployment\"," + + "\"override-values\":[" + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}," + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}" + + "]}}"), + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + db.DBconn = testCase.mockdb + depIntentCli := NewDeploymentIntentGroupClient() + got, err := depIntentCli.GetDeploymentIntentGroup(testCase.inputDeploymentIntentGrp, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("GetDeploymentIntentGroup returned an unexpected error: %s", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("GetDeploymentIntentGroup returned an unexpected error: %s", err) + } + } else { + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("GetDeploymentIntentGroup returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} diff --git a/src/orchestrator/pkg/module/generic_placement_intent.go b/src/orchestrator/pkg/module/generic_placement_intent.go index 4098194e..8e739fc8 100644 --- a/src/orchestrator/pkg/module/generic_placement_intent.go +++ b/src/orchestrator/pkg/module/generic_placement_intent.go @@ -25,20 +25,20 @@ import ( // GenericPlacementIntent shall have 2 fields - metadata and spec type GenericPlacementIntent struct { - MetaData IntentMetaData `json:"metadata"` - Spec IntentSpecData `json:"spec"` + MetaData GenIntentMetaData `json:"metadata"` + Spec GenIntentSpecData `json:"spec"` } -// IntentMetaData has name, description, userdata1, userdata2 -type IntentMetaData struct { +// GenIntentMetaData has name, description, userdata1, userdata2 +type GenIntentMetaData struct { Name string `json:"name"` Description string `json:"description"` UserData1 string `json:"userData1"` UserData2 string `json:"userData2"` } -// IntentSpecData has logical-cloud-name -type IntentSpecData struct { +// GenIntentSpecData has logical-cloud-name +type GenIntentSpecData struct { LogicalCloud string `json:"logical-cloud"` } diff --git a/src/orchestrator/pkg/module/generic_placement_intent_test.go b/src/orchestrator/pkg/module/generic_placement_intent_test.go index 3cb29e61..c87f9ddc 100644 --- a/src/orchestrator/pkg/module/generic_placement_intent_test.go +++ b/src/orchestrator/pkg/module/generic_placement_intent_test.go @@ -38,13 +38,13 @@ func TestCreateGenericPlacementIntent(t *testing.T) { { label: "Create GenericPlacementIntent", inputIntent: GenericPlacementIntent{ - MetaData: IntentMetaData{ + MetaData: GenIntentMetaData{ Name: "testGenericPlacement", Description: " A sample intent for testing", UserData1: "userData1", UserData2: "userData2", }, - Spec: IntentSpecData{ + Spec: GenIntentSpecData{ LogicalCloud: "logicalCloud1", }, }, @@ -52,13 +52,13 @@ func TestCreateGenericPlacementIntent(t *testing.T) { inputCompositeApp: "testCompositeApp", inputCompositeAppVersion: "testCompositeAppVersion", expected: GenericPlacementIntent{ - MetaData: IntentMetaData{ + MetaData: GenIntentMetaData{ Name: "testGenericPlacement", Description: " A sample intent for testing", UserData1: "userData1", UserData2: "userData2", }, - Spec: IntentSpecData{ + Spec: GenIntentSpecData{ LogicalCloud: "logicalCloud1", }, }, @@ -128,13 +128,13 @@ func TestGetGenericPlacementIntent(t *testing.T) { compositeAppName: "testCompositeApp", compositeAppVersion: "testVersion", expected: GenericPlacementIntent{ - MetaData: IntentMetaData{ + MetaData: GenIntentMetaData{ Name: "testIntent", Description: "A sample intent for testing", UserData1: "userData1", UserData2: "userData2", }, - Spec: IntentSpecData{ + Spec: GenIntentSpecData{ LogicalCloud: "logicalCloud1", }, }, diff --git a/src/orchestrator/pkg/module/module.go b/src/orchestrator/pkg/module/module.go index 34a84624..b46c6068 100644 --- a/src/orchestrator/pkg/module/module.go +++ b/src/orchestrator/pkg/module/module.go @@ -18,13 +18,15 @@ package module // Client for using the services in the orchestrator type Client struct { - Project *ProjectClient - CompositeApp *CompositeAppClient - Controller *ControllerClient - Cluster *ClusterClient - // Add Clients for API's here + Project *ProjectClient + CompositeApp *CompositeAppClient + Controller *ControllerClient + Cluster *ClusterClient GenericPlacementIntent *GenericPlacementIntentClient AppIntent *AppIntentClient + // Add Clients for API's here + DeploymentIntentGroup *DeploymentIntentGroupClient + Intent *IntentClient } // NewClient creates a new client for using the services @@ -38,6 +40,7 @@ func NewClient() *Client { // Add Client API handlers here c.GenericPlacementIntent = NewGenericPlacementIntentClient() c.AppIntent = NewAppIntentClient() - + c.DeploymentIntentGroup = NewDeploymentIntentGroupClient() + c.Intent = NewIntentClient() return c } |