summaryrefslogtreecommitdiffstats
path: root/src/k8splugin/internal/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/k8splugin/internal/app')
-rw-r--r--src/k8splugin/internal/app/client.go176
-rw-r--r--src/k8splugin/internal/app/client_test.go92
-rw-r--r--src/k8splugin/internal/app/instance.go206
-rw-r--r--src/k8splugin/internal/app/instance_test.go (renamed from src/k8splugin/internal/app/vnfhelper_test.go)232
-rw-r--r--src/k8splugin/internal/app/vnfhelper.go195
5 files changed, 613 insertions, 288 deletions
diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go
index 3555afdd..fa5fdfd5 100644
--- a/src/k8splugin/internal/app/client.go
+++ b/src/k8splugin/internal/app/client.go
@@ -14,31 +14,187 @@ limitations under the License.
package app
import (
- "errors"
+ "log"
+ "os"
+ "strings"
- pkgerrors "github.com/pkg/errors"
+ utils "k8splugin/internal"
+ pkgerrors "github.com/pkg/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
+ "k8s.io/helm/pkg/tiller"
)
-// GetKubeClient loads the Kubernetes configuation values stored into the local configuration file
-var GetKubeClient = func(configPath string) (kubernetes.Clientset, error) {
- var clientset *kubernetes.Clientset
+type kubernetesClient struct {
+ clientSet *kubernetes.Clientset
+}
+// GetKubeClient loads the Kubernetes configuation values stored into the local configuration file
+func (k *kubernetesClient) init(configPath string) error {
if configPath == "" {
- return *clientset, errors.New("config not passed and is not found in ~/.kube. ")
+ return pkgerrors.New("config not passed and is not found in ~/.kube. ")
}
config, err := clientcmd.BuildConfigFromFlags("", configPath)
if err != nil {
- return kubernetes.Clientset{}, pkgerrors.Wrap(err, "setConfig: Build config from flags raised an error")
+ return pkgerrors.Wrap(err, "setConfig: Build config from flags raised an error")
+ }
+
+ k.clientSet, err = kubernetes.NewForConfig(config)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (k *kubernetesClient) ensureNamespace(namespace string) error {
+ namespacePlugin, ok := utils.LoadedPlugins["namespace"]
+ if !ok {
+ return pkgerrors.New("No plugin for namespace resource found")
+ }
+
+ symGetNamespaceFunc, err := namespacePlugin.Lookup("Get")
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error fetching get namespace function")
+ }
+
+ ns, _ := symGetNamespaceFunc.(func(string, string, kubernetes.Interface) (string, error))(
+ namespace, namespace, k.clientSet)
+
+ if ns == "" {
+ log.Println("Creating " + namespace + " namespace")
+ symGetNamespaceFunc, err := namespacePlugin.Lookup("Create")
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error fetching create namespace plugin")
+ }
+ namespaceResource := &utils.ResourceData{
+ Namespace: namespace,
+ }
+
+ _, err = symGetNamespaceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
+ namespaceResource, k.clientSet)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error creating "+namespace+" namespace")
+ }
+ }
+ return nil
+}
+
+func (k *kubernetesClient) createKind(kind string, files []string, namespace string) ([]string, error) {
+
+ log.Println("Processing items of Kind: " + kind)
+
+ //Iterate over each file of a particular kind here
+ var resourcesCreated []string
+ for _, f := range files {
+ if _, err := os.Stat(f); os.IsNotExist(err) {
+ return nil, pkgerrors.New("File " + f + "does not exists")
+ }
+
+ log.Println("Processing file: " + f)
+
+ //Populate the namespace from profile instead of instance body
+ genericKubeData := &utils.ResourceData{
+ YamlFilePath: f,
+ Namespace: namespace,
+ }
+
+ typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
+ if !ok {
+ return nil, pkgerrors.New("No plugin for kind " + kind + " found")
+ }
+
+ symCreateResourceFunc, err := typePlugin.Lookup("Create")
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Error fetching "+kind+" plugin")
+ }
+
+ createdResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
+ genericKubeData, k.clientSet)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Error in plugin "+kind+" plugin")
+ }
+ log.Print(createdResourceName + " created")
+ resourcesCreated = append(resourcesCreated, createdResourceName)
+ }
+
+ return resourcesCreated, nil
+}
+
+func (k *kubernetesClient) createResources(resMap map[string][]string,
+ namespace string) (map[string][]string, error) {
+
+ err := k.ensureNamespace(namespace)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Creating Namespace")
+ }
+
+ createdResourceMap := make(map[string][]string)
+ // Create all the known kinds in the InstallOrder
+ for _, kind := range tiller.InstallOrder {
+ files, ok := resMap[kind]
+ if !ok {
+ log.Println("Kind " + kind + " not found. Skipping...")
+ continue
+ }
+
+ resourcesCreated, err := k.createKind(kind, files, namespace)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Error creating kind: "+kind)
+ }
+
+ createdResourceMap[kind] = resourcesCreated
+ delete(resMap, kind)
}
- clientset, err = kubernetes.NewForConfig(config)
+ //Create the remaining kinds from the resMap
+ for kind, files := range resMap {
+ resourcesCreated, err := k.createKind(kind, files, namespace)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Error creating kind: "+kind)
+ }
+
+ createdResourceMap[kind] = resourcesCreated
+ delete(resMap, kind)
+ }
+
+ return createdResourceMap, nil
+}
+
+func (k *kubernetesClient) deleteKind(kind string, resources []string, namespace string) error {
+ log.Println("Deleting items of Kind: " + kind)
+
+ typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
+ if !ok {
+ return pkgerrors.New("No plugin for resource " + kind + " found")
+ }
+
+ symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
if err != nil {
- return *clientset, err
+ return pkgerrors.Wrap(err, "Error fetching "+kind+" plugin")
+ }
+
+ for _, res := range resources {
+ log.Println("Deleting resource: " + res)
+ err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
+ res, namespace, k.clientSet)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error destroying "+res)
+ }
+ }
+ return nil
+}
+
+func (k *kubernetesClient) deleteResources(resMap map[string][]string, namespace string) error {
+ //TODO: Investigate if deletion should be in a particular order
+ for kind, resourceNames := range resMap {
+ err := k.deleteKind(kind, resourceNames, namespace)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Deleting resources")
+ }
}
- return *clientset, nil
+ return nil
}
diff --git a/src/k8splugin/internal/app/client_test.go b/src/k8splugin/internal/app/client_test.go
index 71892725..5999cfa0 100644
--- a/src/k8splugin/internal/app/client_test.go
+++ b/src/k8splugin/internal/app/client_test.go
@@ -14,21 +14,105 @@ limitations under the License.
package app
import (
+ "os"
+ "plugin"
"reflect"
"testing"
+
+ utils "k8splugin/internal"
+
+ pkgerrors "github.com/pkg/errors"
+ "k8s.io/client-go/kubernetes"
)
-func TestGetKubeClient(t *testing.T) {
+func LoadMockPlugins(krdLoadedPlugins map[string]*plugin.Plugin) error {
+ if _, err := os.Stat("../../mock_files/mock_plugins/mockplugin.so"); os.IsNotExist(err) {
+ return pkgerrors.New("mockplugin.so does not exist. Please compile mockplugin.go to generate")
+ }
+
+ mockPlugin, err := plugin.Open("../../mock_files/mock_plugins/mockplugin.so")
+ if err != nil {
+ return pkgerrors.Wrap(err, "Opening mock plugins")
+ }
+
+ krdLoadedPlugins["namespace"] = mockPlugin
+ krdLoadedPlugins["deployment"] = mockPlugin
+ krdLoadedPlugins["service"] = mockPlugin
+
+ return nil
+}
+
+func TestInit(t *testing.T) {
t.Run("Successfully create Kube Client", func(t *testing.T) {
- clientset, err := GetKubeClient("../../mock_files/mock_configs/mock_config")
+ kubeClient := kubernetesClient{}
+ err := kubeClient.init("../../mock_files/mock_configs/mock_config")
if err != nil {
t.Fatalf("TestGetKubeClient returned an error (%s)", err)
}
- if reflect.TypeOf(clientset).Name() != "Clientset" {
- t.Fatalf("TestGetKubeClient returned :\n result=%v\n expected=%v", clientset, "Clientset")
+ name := reflect.TypeOf(kubeClient.clientSet).Elem().Name()
+ if name != "Clientset" {
+ t.Fatalf("TestGetKubeClient returned :\n result=%v\n expected=%v", name, "Clientset")
}
})
}
+
+func TestCreateResources(t *testing.T) {
+ oldkrdPluginData := utils.LoadedPlugins
+
+ defer func() {
+ utils.LoadedPlugins = oldkrdPluginData
+ }()
+
+ err := LoadMockPlugins(utils.LoadedPlugins)
+ if err != nil {
+ t.Fatalf("LoadMockPlugins returned an error (%s)", err)
+ }
+
+ k8 := kubernetesClient{
+ clientSet: &kubernetes.Clientset{},
+ }
+
+ t.Run("Successfully delete resources", func(t *testing.T) {
+ data := map[string][]string{
+ "Deployment": []string{"../../mock_files/mock_yamls/deployment.yaml"},
+ "Service": []string{"../../mock_files/mock_yamls/service.yaml"},
+ }
+
+ _, err := k8.createResources(data, "testnamespace")
+ if err != nil {
+ t.Fatalf("TestCreateResources returned an error (%s)", err)
+ }
+ })
+}
+
+func TestDeleteResources(t *testing.T) {
+ oldkrdPluginData := utils.LoadedPlugins
+
+ defer func() {
+ utils.LoadedPlugins = oldkrdPluginData
+ }()
+
+ err := LoadMockPlugins(utils.LoadedPlugins)
+ if err != nil {
+ t.Fatalf("LoadMockPlugins returned an error (%s)", err)
+ }
+
+ k8 := kubernetesClient{
+ clientSet: &kubernetes.Clientset{},
+ }
+
+ t.Run("Successfully delete resources", func(t *testing.T) {
+ data := map[string][]string{
+ "Deployment": []string{"deployment-1", "deployment-2"},
+ "Service": []string{"service-1", "service-2"},
+ }
+
+ err := k8.deleteResources(data, "test")
+ if err != nil {
+ t.Fatalf("TestCreateVNF returned an error (%s)", err)
+ }
+ })
+}
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
new file mode 100644
index 00000000..a5b35fef
--- /dev/null
+++ b/src/k8splugin/internal/app/instance.go
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "math/rand"
+ "os"
+
+ "k8splugin/internal/db"
+ "k8splugin/internal/rb"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+// InstanceRequest contains the parameters needed for instantiation
+// of profiles
+type InstanceRequest struct {
+ RBName string `json:"rb-name"`
+ RBVersion string `json:"rb-version"`
+ ProfileName string `json:"profile-name"`
+ CloudRegion string `json:"cloud-region"`
+ Labels map[string]string `json:"labels"`
+}
+
+// InstanceResponse contains the response from instantiation
+type InstanceResponse struct {
+ ID string `json:"id"`
+ RBName string `json:"rb-name"`
+ RBVersion string `json:"rb-version"`
+ ProfileName string `json:"profile-name"`
+ CloudRegion string `json:"cloud-region"`
+ Namespace string `json:"namespace"`
+ Resources map[string][]string `json:"resources"`
+}
+
+// InstanceManager is an interface exposes the instantiation functionality
+type InstanceManager interface {
+ Create(i InstanceRequest) (InstanceResponse, error)
+ Get(id string) (InstanceResponse, error)
+ Delete(id string) error
+}
+
+// InstanceKey is used as the primary key in the db
+type InstanceKey struct {
+ ID string `json:"id"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (dk InstanceKey) String() string {
+ out, err := json.Marshal(dk)
+ if err != nil {
+ return ""
+ }
+
+ return string(out)
+}
+
+// InstanceClient implements the InstanceManager interface
+// It will also be used to maintain some localized state
+type InstanceClient struct {
+ storeName string
+ tagInst string
+}
+
+// Using 6 bytes of randomness to generate an 8 character string
+func generateInstanceID() string {
+ b := make([]byte, 6)
+ rand.Read(b)
+ return base64.URLEncoding.EncodeToString(b)
+}
+
+// NewInstanceClient returns an instance of the InstanceClient
+// which implements the InstanceManager
+func NewInstanceClient() *InstanceClient {
+ return &InstanceClient{
+ storeName: "rbdef",
+ tagInst: "instance",
+ }
+}
+
+// Create an entry for the resource bundle profile in the database
+func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
+
+ // Name is required
+ if i.RBName == "" || i.RBVersion == "" || i.ProfileName == "" || i.CloudRegion == "" {
+ return InstanceResponse{},
+ pkgerrors.New("RBName, RBversion, ProfileName, CloudRegion are required to create a new instance")
+ }
+
+ //Check if profile exists
+ profile, err := rb.NewProfileClient().Get(i.RBName, i.RBVersion, i.ProfileName)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.New("Unable to find Profile to create instance")
+ }
+
+ overrideValues := []string{}
+
+ //Execute the kubernetes create command
+ resMap, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
+ }
+
+ k8sClient := kubernetesClient{}
+ err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + i.CloudRegion)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information")
+ }
+
+ createdResources, err := k8sClient.createResources(resMap, profile.Namespace)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Create Kubernetes Resources")
+ }
+
+ id := generateInstanceID()
+
+ //Compose the return response
+ resp := InstanceResponse{
+ ID: id,
+ RBName: i.RBName,
+ RBVersion: i.RBVersion,
+ ProfileName: i.ProfileName,
+ CloudRegion: i.CloudRegion,
+ Namespace: profile.Namespace,
+ Resources: createdResources,
+ }
+
+ key := InstanceKey{
+ ID: id,
+ }
+ err = db.DBconn.Create(v.storeName, key, v.tagInst, resp)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Creating Instance DB Entry")
+ }
+
+ return resp, nil
+}
+
+// Get returns the instance for corresponding ID
+func (v *InstanceClient) Get(id string) (InstanceResponse, error) {
+ key := InstanceKey{
+ ID: id,
+ }
+ value, err := db.DBconn.Read(v.storeName, key, v.tagInst)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Get Instance")
+ }
+
+ //value is a byte array
+ if value != nil {
+ resp := InstanceResponse{}
+ err = db.DBconn.Unmarshal(value, &resp)
+ if err != nil {
+ return InstanceResponse{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value")
+ }
+ return resp, nil
+ }
+
+ return InstanceResponse{}, pkgerrors.New("Error getting Instance")
+}
+
+// Delete the Instance from database
+func (v *InstanceClient) Delete(id string) error {
+ inst, err := v.Get(id)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error getting Instance")
+ }
+
+ k8sClient := kubernetesClient{}
+ err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + inst.CloudRegion)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Getting CloudRegion Information")
+ }
+
+ err = k8sClient.deleteResources(inst.Resources, inst.Namespace)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Deleting Instance Resources")
+ }
+
+ key := InstanceKey{
+ ID: id,
+ }
+ err = db.DBconn.Delete(v.storeName, key, v.tagInst)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete Instance")
+ }
+
+ return nil
+}
diff --git a/src/k8splugin/internal/app/vnfhelper_test.go b/src/k8splugin/internal/app/instance_test.go
index 7587e5d6..480569c5 100644
--- a/src/k8splugin/internal/app/vnfhelper_test.go
+++ b/src/k8splugin/internal/app/instance_test.go
@@ -14,73 +14,27 @@ limitations under the License.
package app
import (
- "io/ioutil"
"log"
"os"
- "plugin"
+ "reflect"
"testing"
- pkgerrors "github.com/pkg/errors"
- yaml "gopkg.in/yaml.v2"
- "k8s.io/client-go/kubernetes"
-
utils "k8splugin/internal"
"k8splugin/internal/db"
"k8splugin/internal/rb"
)
-func LoadMockPlugins(krdLoadedPlugins *map[string]*plugin.Plugin) error {
- if _, err := os.Stat("../../mock_files/mock_plugins/mockplugin.so"); os.IsNotExist(err) {
- return pkgerrors.New("mockplugin.so does not exist. Please compile mockplugin.go to generate")
- }
-
- mockPlugin, err := plugin.Open("../../mock_files/mock_plugins/mockplugin.so")
- if err != nil {
- return pkgerrors.Cause(err)
- }
-
- (*krdLoadedPlugins)["namespace"] = mockPlugin
- (*krdLoadedPlugins)["deployment"] = mockPlugin
- (*krdLoadedPlugins)["service"] = mockPlugin
-
- return nil
-}
-
-func TestCreateVNF(t *testing.T) {
+func TestInstanceCreate(t *testing.T) {
oldkrdPluginData := utils.LoadedPlugins
- oldReadMetadataFile := ReadMetadataFile
-
defer func() {
utils.LoadedPlugins = oldkrdPluginData
- ReadMetadataFile = oldReadMetadataFile
}()
-
- err := LoadMockPlugins(&utils.LoadedPlugins)
+ err := LoadMockPlugins(utils.LoadedPlugins)
if err != nil {
- t.Fatalf("TestCreateVNF returned an error (%s)", err)
+ t.Fatalf("LoadMockPlugins returned an error (%s)", err)
}
- ReadMetadataFile = func(yamlFilePath string) (MetadataFile, error) {
- var seqFile MetadataFile
-
- if _, err := os.Stat(yamlFilePath); err == nil {
- rawBytes, err := ioutil.ReadFile("../../mock_files/mock_yamls/metadata.yaml")
- if err != nil {
- return seqFile, pkgerrors.Wrap(err, "Metadata YAML file read error")
- }
-
- err = yaml.Unmarshal(rawBytes, &seqFile)
- if err != nil {
- return seqFile, pkgerrors.Wrap(err, "Metadata YAML file unmarshall error")
- }
- }
-
- return seqFile, nil
- }
-
- kubeclient := kubernetes.Clientset{}
-
- t.Run("Successfully create VNF", func(t *testing.T) {
+ t.Run("Successfully create Instance", func(t *testing.T) {
db.DBconn = &db.MockDB{
Items: map[string]map[string][]byte{
rb.ProfileKey{RBName: "test-rbdef", RBVersion: "v1",
@@ -190,60 +144,180 @@ func TestCreateVNF(t *testing.T) {
},
},
}
- externaluuid, data, err := CreateVNF("uuid", "cloudregion1",
- rb.Profile{
- RBName: "test-rbdef",
- RBVersion: "v1",
- ProfileName: "profile1",
- ReleaseName: "testprofilereleasename",
- Namespace: "testnamespace",
- KubernetesVersion: "1.12.3",
- }, &kubeclient)
+
+ ic := NewInstanceClient()
+ input := InstanceRequest{
+ RBName: "test-rbdef",
+ RBVersion: "v1",
+ ProfileName: "profile1",
+ CloudRegion: "mock_config",
+ }
+
+ err := os.Setenv("KUBE_CONFIG_DIR", "../../mock_files/mock_configs")
if err != nil {
- t.Fatalf("TestCreateVNF returned an error (%s)", err)
+ t.Fatalf("TestInstanceCreate returned an error (%s)", err)
}
- log.Println(externaluuid)
+ ir, err := ic.Create(input)
+ if err != nil {
+ t.Fatalf("TestInstanceCreate returned an error (%s)", err)
+ }
+
+ log.Println(ir)
- if data == nil {
- t.Fatalf("TestCreateVNF returned empty data (%s)", data)
+ if len(ir.Resources) == 0 {
+ t.Fatalf("TestInstanceCreate returned empty data (%s)", ir)
}
})
}
-func TestDeleteVNF(t *testing.T) {
+func TestInstanceGet(t *testing.T) {
oldkrdPluginData := utils.LoadedPlugins
defer func() {
utils.LoadedPlugins = oldkrdPluginData
}()
- err := LoadMockPlugins(&utils.LoadedPlugins)
+ err := LoadMockPlugins(utils.LoadedPlugins)
if err != nil {
- t.Fatalf("TestCreateVNF returned an error (%s)", err)
+ t.Fatalf("LoadMockPlugins returned an error (%s)", err)
}
- kubeclient := kubernetes.Clientset{}
-
- t.Run("Successfully delete VNF", func(t *testing.T) {
- data := map[string][]string{
- "deployment": []string{"cloud1-default-uuid-sisedeploy"},
- "service": []string{"cloud1-default-uuid-sisesvc"},
+ t.Run("Successfully Get Instance", func(t *testing.T) {
+ db.DBconn = &db.MockDB{
+ Items: map[string]map[string][]byte{
+ InstanceKey{ID: "HaKpys8e"}.String(): {
+ "instance": []byte(
+ "{\"profile-name\":\"profile1\"," +
+ "\"id\":\"HaKpys8e\"," +
+ "\"namespace\":\"testnamespace\"," +
+ "\"rb-name\":\"test-rbdef\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"cloud-region\":\"region1\"," +
+ "\"resources\": {" +
+ "\"deployment\": [\"test-deployment\"]," +
+ "\"service\": [\"test-service\"]" +
+ "}}"),
+ },
+ },
}
- err := DestroyVNF(data, "test", &kubeclient)
+ expected := InstanceResponse{
+ ID: "HaKpys8e",
+ RBName: "test-rbdef",
+ RBVersion: "v1",
+ ProfileName: "profile1",
+ CloudRegion: "region1",
+ Namespace: "testnamespace",
+ Resources: map[string][]string{
+ "deployment": []string{"test-deployment"},
+ "service": []string{"test-service"},
+ },
+ }
+ ic := NewInstanceClient()
+ id := "HaKpys8e"
+ data, err := ic.Get(id)
if err != nil {
- t.Fatalf("TestCreateVNF returned an error (%s)", err)
+ t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+ }
+ if !reflect.DeepEqual(expected, data) {
+ t.Fatalf("TestInstanceGet returned:\n result=%v\n expected=%v",
+ data, expected)
+ }
+ })
+
+ t.Run("Get non-existing Instance", func(t *testing.T) {
+ db.DBconn = &db.MockDB{
+ Items: map[string]map[string][]byte{
+ InstanceKey{ID: "HaKpys8e"}.String(): {
+ "instance": []byte(
+ "{\"profile-name\":\"profile1\"," +
+ "\"id\":\"HaKpys8e\"," +
+ "\"namespace\":\"testnamespace\"," +
+ "\"rb-name\":\"test-rbdef\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"cloud-region\":\"mock_config\"," +
+ "\"resources\": {" +
+ "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+ "\"service\": [\"service-1\",\"service-2\"]" +
+ "}}"),
+ },
+ },
+ }
+
+ ic := NewInstanceClient()
+ id := "non-existing"
+ _, err := ic.Get(id)
+ if err == nil {
+ t.Fatal("Expected error, got pass", err)
}
})
}
-func TestReadMetadataFile(t *testing.T) {
- t.Run("Successfully read Metadata YAML file", func(t *testing.T) {
- _, err := ReadMetadataFile("../../mock_files//mock_yamls/metadata.yaml")
+func TestInstanceDelete(t *testing.T) {
+ oldkrdPluginData := utils.LoadedPlugins
+
+ defer func() {
+ utils.LoadedPlugins = oldkrdPluginData
+ }()
+
+ err := LoadMockPlugins(utils.LoadedPlugins)
+ if err != nil {
+ t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+ }
+
+ t.Run("Successfully delete Instance", func(t *testing.T) {
+ db.DBconn = &db.MockDB{
+ Items: map[string]map[string][]byte{
+ InstanceKey{ID: "HaKpys8e"}.String(): {
+ "instance": []byte(
+ "{\"profile-name\":\"profile1\"," +
+ "\"id\":\"HaKpys8e\"," +
+ "\"namespace\":\"testnamespace\"," +
+ "\"rb-name\":\"test-rbdef\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"cloud-region\":\"mock_config\"," +
+ "\"resources\": {" +
+ "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+ "\"service\": [\"service-1\",\"service-2\"]" +
+ "}}"),
+ },
+ },
+ }
+
+ ic := NewInstanceClient()
+ id := "HaKpys8e"
+ err := ic.Delete(id)
if err != nil {
- t.Fatalf("TestReadMetadataFile returned an error (%s)", err)
+ t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+ }
+ })
+
+ t.Run("Delete non-existing Instance", func(t *testing.T) {
+ db.DBconn = &db.MockDB{
+ Items: map[string]map[string][]byte{
+ InstanceKey{ID: "HaKpys8e"}.String(): {
+ "instance": []byte(
+ "{\"profile-name\":\"profile1\"," +
+ "\"id\":\"HaKpys8e\"," +
+ "\"namespace\":\"testnamespace\"," +
+ "\"rb-name\":\"test-rbdef\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"cloud-region\":\"mock_config\"," +
+ "\"resources\": {" +
+ "\"deployment\": [\"deployment-1\",\"deployment-2\"]," +
+ "\"service\": [\"service-1\",\"service-2\"]" +
+ "}}"),
+ },
+ },
+ }
+
+ ic := NewInstanceClient()
+ id := "non-existing"
+ err := ic.Delete(id)
+ if err == nil {
+ t.Fatal("Expected error, got pass", err)
}
})
}
diff --git a/src/k8splugin/internal/app/vnfhelper.go b/src/k8splugin/internal/app/vnfhelper.go
deleted file mode 100644
index c5783d69..00000000
--- a/src/k8splugin/internal/app/vnfhelper.go
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-Copyright 2018 Intel Corporation.
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package app
-
-import (
- "encoding/hex"
- "io/ioutil"
- "log"
- "math/rand"
- "os"
- "strings"
-
- "k8s.io/client-go/kubernetes"
-
- pkgerrors "github.com/pkg/errors"
- yaml "gopkg.in/yaml.v2"
-
- utils "k8splugin/internal"
- "k8splugin/internal/rb"
-)
-
-func generateExternalVNFID() string {
- b := make([]byte, 2)
- rand.Read(b)
- return hex.EncodeToString(b)
-}
-
-func ensuresNamespace(namespace string, kubeclient kubernetes.Interface) error {
- namespacePlugin, ok := utils.LoadedPlugins["namespace"]
- if !ok {
- return pkgerrors.New("No plugin for namespace resource found")
- }
-
- symGetNamespaceFunc, err := namespacePlugin.Lookup("Get")
- if err != nil {
- return pkgerrors.Wrap(err, "Error fetching get namespace function")
- }
-
- ns, _ := symGetNamespaceFunc.(func(string, string, kubernetes.Interface) (string, error))(
- namespace, namespace, kubeclient)
-
- if ns == "" {
- log.Println("Creating " + namespace + " namespace")
- symGetNamespaceFunc, err := namespacePlugin.Lookup("Create")
- if err != nil {
- return pkgerrors.Wrap(err, "Error fetching create namespace plugin")
- }
- namespaceResource := &utils.ResourceData{
- Namespace: namespace,
- }
-
- _, err = symGetNamespaceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
- namespaceResource, kubeclient)
- if err != nil {
- return pkgerrors.Wrap(err, "Error creating "+namespace+" namespace")
- }
- }
- return nil
-}
-
-// CreateVNF reads the CSAR files from the files system and creates them one by one
-var CreateVNF = func(csarID string, cloudRegionID string, profile rb.Profile, kubeclient *kubernetes.Clientset) (string, map[string][]string, error) {
-
- overrideValues := []string{}
- //Make sure that the namespace exists before trying to create any resources
- if err := ensuresNamespace(profile.Namespace, kubeclient); err != nil {
- return "", nil, pkgerrors.Wrap(err, "Error while ensuring namespace: "+profile.Namespace)
- }
- externalVNFID := generateExternalVNFID()
- internalVNFID := cloudRegionID + "-" + profile.Namespace + "-" + externalVNFID
-
- metaMap, err := rb.NewProfileClient().Resolve(profile.RBName, profile.RBVersion, profile.ProfileName, overrideValues)
- if err != nil {
- return "", nil, pkgerrors.Wrap(err, "Error resolving helm charts")
- }
-
- resourceYAMLNameMap := make(map[string][]string)
- // Iterates over the resources defined in the metadata map to create kubernetes resources
- log.Printf("%d resource(s) type(s) to be processed", len(metaMap))
- for res, filePaths := range metaMap {
- //Convert resource to lower case as the map index is lowercase
- resource := strings.ToLower(res)
- log.Println("Processing items of " + string(resource) + " resource")
- var resourcesCreated []string
- for _, filepath := range filePaths {
-
- if _, err := os.Stat(filepath); os.IsNotExist(err) {
- return "", nil, pkgerrors.New("File " + filepath + "does not exists")
- }
- log.Println("Processing file: " + filepath)
-
- //Populate the namespace from profile instead of instance body
- genericKubeData := &utils.ResourceData{
- YamlFilePath: filepath,
- Namespace: profile.Namespace,
- VnfId: internalVNFID,
- }
-
- typePlugin, ok := utils.LoadedPlugins[resource]
- if !ok {
- return "", nil, pkgerrors.New("No plugin for resource " + resource + " found")
- }
-
- symCreateResourceFunc, err := typePlugin.Lookup("Create")
- if err != nil {
- return "", nil, pkgerrors.Wrap(err, "Error fetching "+resource+" plugin")
- }
-
- internalResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
- genericKubeData, kubeclient)
- if err != nil {
- return "", nil, pkgerrors.Wrap(err, "Error in plugin "+resource+" plugin")
- }
- log.Print(internalResourceName + " succesful resource created")
- resourcesCreated = append(resourcesCreated, internalResourceName)
- }
- resourceYAMLNameMap[resource] = resourcesCreated
- }
-
- return externalVNFID, resourceYAMLNameMap, nil
-}
-
-// DestroyVNF deletes VNFs based on data passed
-var DestroyVNF = func(data map[string][]string, namespace string, kubeclient *kubernetes.Clientset) error {
- /* data:
- {
- "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
- "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
- },
- */
-
- for resourceName, resourceList := range data {
- typePlugin, ok := utils.LoadedPlugins[resourceName]
- if !ok {
- return pkgerrors.New("No plugin for resource " + resourceName + " found")
- }
-
- symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
- if err != nil {
- return pkgerrors.Wrap(err, "Error fetching "+resourceName+" plugin")
- }
-
- for _, resourceName := range resourceList {
-
- log.Println("Deleting resource: " + resourceName)
-
- err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
- resourceName, namespace, kubeclient)
- if err != nil {
- return pkgerrors.Wrap(err, "Error destroying "+resourceName)
- }
- }
- }
-
- return nil
-}
-
-// MetadataFile stores the metadata of execution
-type MetadataFile struct {
- ResourceTypePathMap map[string][]string `yaml:"resources"`
-}
-
-// ReadMetadataFile reads the metadata yaml to return the order or reads
-var ReadMetadataFile = func(path string) (MetadataFile, error) {
- var metadataFile MetadataFile
-
- if _, err := os.Stat(path); os.IsNotExist(err) {
- return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file does not exist")
- }
-
- log.Println("Reading metadata YAML: " + path)
- yamlFile, err := ioutil.ReadFile(path)
- if err != nil {
- return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file read error")
- }
-
- err = yaml.Unmarshal(yamlFile, &metadataFile)
- if err != nil {
- return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file unmarshal error")
- }
- log.Printf("metadata:\n%v", metadataFile)
-
- return metadataFile, nil
-}