From 8e0c4c63e5a014c95805f16d30a64cd53ddc7385 Mon Sep 17 00:00:00 2001 From: Dileep Ranganathan Date: Wed, 19 Feb 2020 16:19:18 -0800 Subject: Composite Profile API and Handler Implemented Composite Profile API and handler, adding create, get and delete handlers for the composite profile. Issue-ID: MULTICLOUD-997 Signed-off-by: Eric Multanen Signed-off-by: Dileep Ranganathan Change-Id: Iab105cf88ef4635038cd36e90f3251bc900b2faf --- src/orchestrator/pkg/module/composite_profile.go | 192 +++++++++++++++++++++ .../pkg/module/composite_profile_test.go | 175 +++++++++++++++++++ src/orchestrator/pkg/module/module.go | 9 +- 3 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 src/orchestrator/pkg/module/composite_profile.go create mode 100644 src/orchestrator/pkg/module/composite_profile_test.go (limited to 'src/orchestrator/pkg') diff --git a/src/orchestrator/pkg/module/composite_profile.go b/src/orchestrator/pkg/module/composite_profile.go new file mode 100644 index 00000000..dca2116a --- /dev/null +++ b/src/orchestrator/pkg/module/composite_profile.go @@ -0,0 +1,192 @@ +/* + * 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" + + pkgerrors "github.com/pkg/errors" +) + +// CompositeProfile contains the parameters needed for CompositeProfiles +// It implements the interface for managing the CompositeProfiles +type CompositeProfile struct { + Metadata CompositeProfileMetadata `json:"metadata"` +} + +// CompositeProfileMetadata contains the metadata for CompositeProfiles +type CompositeProfileMetadata struct { + Name string `json:"name"` + Description string `json:"description"` + UserData1 string `json:"userData1"` + UserData2 string `json:"userData2"` +} + +// CompositeProfileKey is the key structure that is used in the database +type CompositeProfileKey struct { + Name string `json:"compositeprofile"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + Version string `json:"compositeappversion"` +} + +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (cpk CompositeProfileKey) String() string { + out, err := json.Marshal(cpk) + if err != nil { + return "" + } + + return string(out) +} + +// CompositeProfileManager exposes the CompositeProfile functionality +type CompositeProfileManager interface { + CreateCompositeProfile(cpf CompositeProfile, p string, ca string, + v string) (CompositeProfile, error) + GetCompositeProfile(compositeProfileName string, projectName string, + compositeAppName string, version string) (CompositeProfile, error) + GetCompositeProfiles(projectName string, compositeAppName string, + version string) ([]CompositeProfile, error) + DeleteCompositeProfile(compositeProfileName string, projectName string, + compositeAppName string, version string) error +} + +// CompositeProfileClient implements the Manager +// It will also be used to maintain some localized state +type CompositeProfileClient struct { + storeName string + tagMeta string +} + +// NewCompositeProfileClient returns an instance of the CompositeProfileClient +// which implements the Manager +func NewCompositeProfileClient() *CompositeProfileClient { + return &CompositeProfileClient{ + storeName: "orchestrator", + tagMeta: "compositeprofilemetadata", + } +} + +// CreateCompositeProfile creates an entry for CompositeProfile in the database. Other Input parameters for it - projectName, compositeAppName, version +func (c *CompositeProfileClient) CreateCompositeProfile(cpf CompositeProfile, p string, ca string, + v string) (CompositeProfile, error) { + + res, err := c.GetCompositeProfile(cpf.Metadata.Name, p, ca, v) + if res != (CompositeProfile{}) { + return CompositeProfile{}, pkgerrors.New("CompositeProfile already exists") + } + + //Check if project exists + _, err = NewProjectClient().GetProject(p) + if err != nil { + return CompositeProfile{}, pkgerrors.New("Unable to find the project") + } + + // check if compositeApp exists + _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p) + if err != nil { + return CompositeProfile{}, pkgerrors.New("Unable to find the composite-app") + } + + cProfkey := CompositeProfileKey{ + Name: cpf.Metadata.Name, + Project: p, + CompositeApp: ca, + Version: v, + } + + err = db.DBconn.Insert(c.storeName, cProfkey, nil, c.tagMeta, cpf) + if err != nil { + return CompositeProfile{}, pkgerrors.Wrap(err, "Create DB entry error") + } + + return cpf, nil +} + +// GetCompositeProfile shall take arguments - name of the composite profile, name of //// the project, name of the composite app and version of the composite app. It shall return the CompositeProfile if its present. +func (c *CompositeProfileClient) GetCompositeProfile(cpf string, p string, ca string, v string) (CompositeProfile, error) { + key := CompositeProfileKey{ + Name: cpf, + Project: p, + CompositeApp: ca, + Version: v, + } + + result, err := db.DBconn.Find(c.storeName, key, c.tagMeta) + if err != nil { + return CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profile error") + } + + if result != nil { + cProf := CompositeProfile{} + err = db.DBconn.Unmarshal(result[0], &cProf) + if err != nil { + return CompositeProfile{}, pkgerrors.Wrap(err, "Unmarshalling CompositeProfile") + } + return cProf, nil + } + + return CompositeProfile{}, pkgerrors.New("Error getting CompositeProfile") +} + +// GetCompositeProfile shall take arguments - name of the composite profile, name of //// the project, name of the composite app and version of the composite app. It shall return the CompositeProfile if its present. +func (c *CompositeProfileClient) GetCompositeProfiles(p string, ca string, v string) ([]CompositeProfile, error) { + key := CompositeProfileKey{ + Name: "", + Project: p, + CompositeApp: ca, + Version: v, + } + + values, err := db.DBconn.Find(c.storeName, key, c.tagMeta) + if err != nil { + return []CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profiles error") + } + + var resp []CompositeProfile + + for _, value := range values { + cp := CompositeProfile{} + err = db.DBconn.Unmarshal(value, &cp) + if err != nil { + return []CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profiles unmarshalling error") + } + resp = append(resp, cp) + } + + return resp, nil +} + +// DeleteCompositeProfile the intent from the database +func (c *CompositeProfileClient) DeleteCompositeProfile(cpf string, p string, ca string, v string) error { + key := CompositeProfileKey{ + Name: cpf, + Project: p, + CompositeApp: ca, + Version: v, + } + + err := db.DBconn.Remove(c.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete CompositeProfile entry;") + } + return nil +} diff --git a/src/orchestrator/pkg/module/composite_profile_test.go b/src/orchestrator/pkg/module/composite_profile_test.go new file mode 100644 index 00000000..af0dd7b7 --- /dev/null +++ b/src/orchestrator/pkg/module/composite_profile_test.go @@ -0,0 +1,175 @@ +/* + * 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 + +//pkgerrors "github.com/pkg/errors" + +/* TODO - db.MockDB needs to be enhanced and then these can be fixed up +func TestCreateCompositeProfile(t *testing.T) { + testCases := []struct { + label string + compositeProfile CompositeProfile + projectName string + compositeApp string + compositeAppVersion string + expectedError string + mockdb *db.MockDB + expected CompositeProfile + }{ + { + label: "Create CompositeProfile", + compositeProfile: CompositeProfile{ + Metadata: CompositeProfileMetadata{ + Name: "testCompositeProfile", + Description: "A sample Composite Profile for testing", + UserData1: "userData1", + UserData2: "userData2", + }, + }, + projectName: "testProject", + compositeApp: "testCompositeApp", + compositeAppVersion: "v1", + expected: CompositeProfile{ + Metadata: CompositeProfileMetadata{ + Name: "testCompositeProfile", + Description: "A sample Composite Profile for testing", + UserData1: "userData1", + UserData2: "userData2", + }, + }, + expectedError: "", + mockdb: &db.MockDB{ + Items: map[string]map[string][]byte{ + ProjectKey{ProjectName: "testProject"}.String(): { + "projectmetadata": []byte( + "{" + + "\"metadata\" : {" + + "\"Name\":\"testProject\"," + + "\"Description\":\"Test project for unit testing\"," + + "\"UserData1\": \"userData1\"," + + "\"UserData2\":\"userData2\"}" + + "}"), + }, + CompositeAppKey{CompositeAppName: "testCompositeApp", Project: "testProject", Version: "v1"}.String(): { + "compositeAppmetadata": []byte( + "{" + + "\"metadata\" : {" + + "\"Name\":\"testCompositeApp\"," + + "\"Description\":\"Test Composite App for unit testing\"," + + "\"UserData1\": \"userData1\"," + + "\"UserData2\":\"userData2\"}," + + "\"spec\": {" + + "\"Version\": \"v1\"}" + + "}"), + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + db.DBconn = testCase.mockdb + cprofCli := NewCompositeProfileClient() + got, err := cprofCli.CreateCompositeProfile(testCase.compositeProfile, testCase.projectName, testCase.compositeApp, testCase.compositeAppVersion) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("CreateCompositeProfile returned an unexpected error %s", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("CreateCompositeProfile returned an unexpected error %s", err) + } + } else { + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("CreateCompositeProfile returned unexpected body: got %v; "+" expected %v", got, testCase.expected) + } + } + }) + + } +} + +func TestGetCompositeProfile(t *testing.T) { + + testCases := []struct { + label string + expectedError string + expected CompositeProfile + mockdb *db.MockDB + compositeProfileName string + projectName string + compositeAppName string + compositeAppVersion string + }{ + { + label: "Get CompositeProfile", + compositeProfileName: "testCompositeProfile", + projectName: "testProject", + compositeAppName: "testCompositeApp", + compositeAppVersion: "v1", + expected: CompositeProfile{ + Metadata: CompositeProfileMetadata{ + Name: "testCompositeProfile", + Description: "A sample CompositeProfile for testing", + UserData1: "userData1", + UserData2: "userData2", + }, + }, + expectedError: "", + mockdb: &db.MockDB{ + Items: map[string]map[string][]byte{ + CompositeProfileKey{ + Name: "testCompositeProfile", + Project: "testProject", + CompositeApp: "testCompositeApp", + Version: "v1", + }.String(): { + "compositeprofile": []byte( + "{\"metadata\":{\"Name\":\"testCompositeProfile\"," + + "\"Description\":\"A sample CompositeProfile for testing\"," + + "\"UserData1\": \"userData1\"," + + "\"UserData2\": \"userData2\"}}"), + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + db.DBconn = testCase.mockdb + cprofCli := NewCompositeProfileClient() + got, err := cprofCli.GetCompositeProfile(testCase.compositeProfileName, testCase.projectName, testCase.compositeAppName, testCase.compositeAppVersion) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("GetCompositeProfile returned an unexpected error: %s", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("GetCompositeProfile returned an unexpected error: %s", err) + } + } else { + if reflect.DeepEqual(testCase.expected, got) == false { + t.Errorf("GetCompositeProfile returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + + }) + } + +} +*/ diff --git a/src/orchestrator/pkg/module/module.go b/src/orchestrator/pkg/module/module.go index b46c6068..fb46b895 100644 --- a/src/orchestrator/pkg/module/module.go +++ b/src/orchestrator/pkg/module/module.go @@ -24,23 +24,24 @@ type Client struct { Cluster *ClusterClient GenericPlacementIntent *GenericPlacementIntentClient AppIntent *AppIntentClient + DeploymentIntentGroup *DeploymentIntentGroupClient + Intent *IntentClient + CompositeProfile *CompositeProfileClient // Add Clients for API's here - DeploymentIntentGroup *DeploymentIntentGroupClient - Intent *IntentClient } // NewClient creates a new client for using the services func NewClient() *Client { c := &Client{} - // Add Client API handlers here c.Project = NewProjectClient() c.CompositeApp = NewCompositeAppClient() c.Controller = NewControllerClient() c.Cluster = NewClusterClient() - // Add Client API handlers here c.GenericPlacementIntent = NewGenericPlacementIntentClient() c.AppIntent = NewAppIntentClient() c.DeploymentIntentGroup = NewDeploymentIntentGroupClient() c.Intent = NewIntentClient() + c.CompositeProfile = NewCompositeProfileClient() + // Add Client API handlers here return c } -- cgit 1.2.3-korg