Replace Kind with GroupVersionKind 24/85524/1
authorKiran Kamineni <kiran.k.kamineni@intel.com>
Wed, 17 Apr 2019 01:09:13 +0000 (18:09 -0700)
committerKiran Kamineni <kiran.k.kamineni@intel.com>
Wed, 17 Apr 2019 01:09:27 +0000 (18:09 -0700)
Kind is not unique to track resources in Kubernetes
GroupVersionKind is unique. We are just using that to
track our data. It is abstracted behind a couple of new
types for templates and resources.
This change makes a lot of the old kind based operations
redundant and simplified.

Issue-ID: MULTICLOUD-573
Change-Id: I8f4ded2ba6a0821a8fbd679dc99ce3a44d805524
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
13 files changed:
src/k8splugin/api/brokerhandler.go
src/k8splugin/api/brokerhandler_test.go
src/k8splugin/api/instancehandler_test.go
src/k8splugin/internal/app/client.go
src/k8splugin/internal/app/client_test.go
src/k8splugin/internal/app/instance.go
src/k8splugin/internal/app/instance_test.go
src/k8splugin/internal/helm/helm.go
src/k8splugin/internal/helm/helm_test.go
src/k8splugin/internal/helm/types.go [new file with mode: 0644]
src/k8splugin/internal/rb/config_backend.go
src/k8splugin/internal/rb/profile.go
src/k8splugin/plugins/generic/plugin.go

index 28e4423..80ab643 100644 (file)
@@ -19,6 +19,7 @@ import (
        "net/http"
 
        "k8splugin/internal/app"
+       "k8splugin/internal/helm"
 
        "github.com/gorilla/mux"
 )
@@ -44,9 +45,9 @@ type brokerRequest struct {
 }
 
 type brokerPOSTResponse struct {
-       TemplateType     string              `json:"template_type"`
-       WorkloadID       string              `json:"workload_id"`
-       TemplateResponse map[string][]string `json:"template_response"`
+       TemplateType     string                    `json:"template_type"`
+       WorkloadID       string                    `json:"workload_id"`
+       TemplateResponse []helm.KubernetesResource `json:"template_response"`
 }
 
 type brokerGETResponse struct {
index 57557ac..d9991e6 100644 (file)
@@ -24,8 +24,10 @@ import (
        "testing"
 
        "k8splugin/internal/app"
+       "k8splugin/internal/helm"
 
        pkgerrors "github.com/pkg/errors"
+       "k8s.io/apimachinery/pkg/runtime/schema"
 )
 
 func TestBrokerCreateHandler(t *testing.T) {
@@ -68,9 +70,21 @@ func TestBrokerCreateHandler(t *testing.T) {
                        expected: brokerPOSTResponse{
                                WorkloadID:   "HaKpys8e",
                                TemplateType: "heat",
-                               TemplateResponse: map[string][]string{
-                                       "deployment": []string{"test-deployment"},
-                                       "service":    []string{"test-service"},
+                               TemplateResponse: []helm.KubernetesResource{
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "apps",
+                                                       Version: "v1",
+                                                       Kind:    "Deployment"},
+                                               Name: "test-deployment",
+                                       },
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "",
+                                                       Version: "v1",
+                                                       Kind:    "Service"},
+                                               Name: "test-service",
+                                       },
                                },
                        },
                        expectedCode: http.StatusCreated,
@@ -83,9 +97,21 @@ func TestBrokerCreateHandler(t *testing.T) {
                                                ProfileName: "profile1",
                                                CloudRegion: "region1",
                                                Namespace:   "testnamespace",
-                                               Resources: map[string][]string{
-                                                       "deployment": []string{"test-deployment"},
-                                                       "service":    []string{"test-service"},
+                                               Resources: []helm.KubernetesResource{
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "apps",
+                                                                       Version: "v1",
+                                                                       Kind:    "Deployment"},
+                                                               Name: "test-deployment",
+                                                       },
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "",
+                                                                       Version: "v1",
+                                                                       Kind:    "Service"},
+                                                               Name: "test-service",
+                                                       },
                                                },
                                        },
                                },
@@ -154,9 +180,21 @@ func TestBrokerGetHandler(t *testing.T) {
                                                ProfileName: "profile1",
                                                CloudRegion: "region1",
                                                Namespace:   "testnamespace",
-                                               Resources: map[string][]string{
-                                                       "deployment": []string{"test-deployment"},
-                                                       "service":    []string{"test-service"},
+                                               Resources: []helm.KubernetesResource{
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "apps",
+                                                                       Version: "v1",
+                                                                       Kind:    "Deployment"},
+                                                               Name: "test-deployment",
+                                                       },
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "",
+                                                                       Version: "v1",
+                                                                       Kind:    "Service"},
+                                                               Name: "test-service",
+                                                       },
                                                },
                                        },
                                },
index ed7135a..6d2abf6 100644 (file)
@@ -24,9 +24,11 @@ import (
        "testing"
 
        "k8splugin/internal/app"
+       "k8splugin/internal/helm"
 
        "github.com/gorilla/mux"
        pkgerrors "github.com/pkg/errors"
+       "k8s.io/apimachinery/pkg/runtime/schema"
 )
 
 //Creating an embedded interface via anonymous variable
@@ -108,9 +110,21 @@ func TestInstanceCreateHandler(t *testing.T) {
                                ProfileName: "profile1",
                                CloudRegion: "region1",
                                Namespace:   "testnamespace",
-                               Resources: map[string][]string{
-                                       "deployment": []string{"test-deployment"},
-                                       "service":    []string{"test-service"},
+                               Resources: []helm.KubernetesResource{
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "apps",
+                                                       Version: "v1",
+                                                       Kind:    "Deployment"},
+                                               Name: "test-deployment",
+                                       },
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "",
+                                                       Version: "v1",
+                                                       Kind:    "Service"},
+                                               Name: "test-service",
+                                       },
                                },
                        },
                        expectedCode: http.StatusCreated,
@@ -123,9 +137,21 @@ func TestInstanceCreateHandler(t *testing.T) {
                                                ProfileName: "profile1",
                                                CloudRegion: "region1",
                                                Namespace:   "testnamespace",
-                                               Resources: map[string][]string{
-                                                       "deployment": []string{"test-deployment"},
-                                                       "service":    []string{"test-service"},
+                                               Resources: []helm.KubernetesResource{
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "apps",
+                                                                       Version: "v1",
+                                                                       Kind:    "Deployment"},
+                                                               Name: "test-deployment",
+                                                       },
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "",
+                                                                       Version: "v1",
+                                                                       Kind:    "Service"},
+                                                               Name: "test-service",
+                                                       },
                                                },
                                        },
                                },
@@ -183,9 +209,21 @@ func TestInstanceGetHandler(t *testing.T) {
                                ProfileName: "profile1",
                                CloudRegion: "region1",
                                Namespace:   "testnamespace",
-                               Resources: map[string][]string{
-                                       "deployment": []string{"test-deployment"},
-                                       "service":    []string{"test-service"},
+                               Resources: []helm.KubernetesResource{
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "apps",
+                                                       Version: "v1",
+                                                       Kind:    "Deployment"},
+                                               Name: "test-deployment",
+                                       },
+                                       {
+                                               GVK: schema.GroupVersionKind{
+                                                       Group:   "",
+                                                       Version: "v1",
+                                                       Kind:    "Service"},
+                                               Name: "test-service",
+                                       },
                                },
                        },
                        instClient: &mockInstanceClient{
@@ -197,9 +235,21 @@ func TestInstanceGetHandler(t *testing.T) {
                                                ProfileName: "profile1",
                                                CloudRegion: "region1",
                                                Namespace:   "testnamespace",
-                                               Resources: map[string][]string{
-                                                       "deployment": []string{"test-deployment"},
-                                                       "service":    []string{"test-service"},
+                                               Resources: []helm.KubernetesResource{
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "apps",
+                                                                       Version: "v1",
+                                                                       Kind:    "Deployment"},
+                                                               Name: "test-deployment",
+                                                       },
+                                                       {
+                                                               GVK: schema.GroupVersionKind{
+                                                                       Group:   "",
+                                                                       Version: "v1",
+                                                                       Kind:    "Service"},
+                                                               Name: "test-service",
+                                                       },
                                                },
                                        },
                                },
index 9b8873c..7024420 100644 (file)
@@ -19,6 +19,7 @@ import (
        "strings"
 
        utils "k8splugin/internal"
+       "k8splugin/internal/helm"
 
        pkgerrors "github.com/pkg/errors"
        "k8s.io/apimachinery/pkg/api/meta"
@@ -27,13 +28,12 @@ import (
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/restmapper"
        "k8s.io/client-go/tools/clientcmd"
-       "k8s.io/helm/pkg/tiller"
 )
 
 // PluginReference is the interface that is implemented
 type PluginReference interface {
        Create(yamlFilePath string, namespace string, client *KubernetesClient) (string, error)
-       Delete(kind string, name string, namespace string, client *KubernetesClient) error
+       Delete(resource helm.KubernetesResource, namespace string, client *KubernetesClient) error
 }
 
 type KubernetesClient struct {
@@ -105,141 +105,124 @@ func (k *KubernetesClient) ensureNamespace(namespace string) error {
        return nil
 }
 
-func (k *KubernetesClient) createGeneric(kind string, files []string, namespace string) ([]string, error) {
+func (k *KubernetesClient) createGeneric(resTempl helm.KubernetesResourceTemplate,
+       namespace string) (helm.KubernetesResource, error) {
 
-       log.Println("Processing items of Kind: " + kind)
+       log.Println("Processing Kind: " + resTempl.GVK.Kind)
 
        //Check if have the mapper before loading the plugin
        err := k.updateMapper()
        if err != nil {
-               return nil, pkgerrors.Wrap(err, "Unable to create RESTMapper")
+               return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Unable to create RESTMapper")
        }
 
        pluginObject, ok := utils.LoadedPlugins["generic"]
        if !ok {
-               return nil, pkgerrors.New("No generic plugin found")
+               return helm.KubernetesResource{}, pkgerrors.New("No generic plugin found")
        }
 
        symbol, err := pluginObject.Lookup("ExportedVariable")
        if err != nil {
-               return nil, pkgerrors.Wrap(err, "No ExportedVariable symbol found")
+               return helm.KubernetesResource{}, pkgerrors.Wrap(err, "No ExportedVariable symbol found")
        }
 
        //Assert if it implements the PluginReference interface
        genericPlugin, ok := symbol.(PluginReference)
        if !ok {
-               return nil, pkgerrors.New("ExportedVariable is not PluginReference type")
+               return helm.KubernetesResource{}, pkgerrors.New("ExportedVariable is not PluginReference type")
        }
 
-       //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)
+       if _, err := os.Stat(resTempl.FilePath); os.IsNotExist(err) {
+               return helm.KubernetesResource{}, pkgerrors.New("File " + resTempl.FilePath + "does not exists")
+       }
 
-               name, err := genericPlugin.Create(f, namespace, k)
-               if err != nil {
-                       return nil, pkgerrors.Wrap(err, "Error in generic plugin")
-               }
+       log.Println("Processing file: " + resTempl.FilePath)
 
-               resourcesCreated = append(resourcesCreated, name)
+       name, err := genericPlugin.Create(resTempl.FilePath, namespace, k)
+       if err != nil {
+               return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error in generic plugin")
        }
-       return resourcesCreated, nil
-}
 
-func (k *KubernetesClient) createKind(kind string, files []string, namespace string) ([]string, error) {
+       return helm.KubernetesResource{
+               GVK:  resTempl.GVK,
+               Name: name,
+       }, nil
+}
 
-       log.Println("Processing items of Kind: " + kind)
+func (k *KubernetesClient) createKind(resTempl helm.KubernetesResourceTemplate,
+       namespace string) (helm.KubernetesResource, error) {
 
-       //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 Kind: " + resTempl.GVK.Kind)
 
-               log.Println("Processing file: " + f)
+       if _, err := os.Stat(resTempl.FilePath); os.IsNotExist(err) {
+               return helm.KubernetesResource{}, pkgerrors.New("File " + resTempl.FilePath + "does not exists")
+       }
 
-               //Populate the namespace from profile instead of instance body
-               genericKubeData := &utils.ResourceData{
-                       YamlFilePath: f,
-                       Namespace:    namespace,
-               }
+       log.Println("Processing file: " + resTempl.FilePath)
 
-               typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
-               if !ok {
-                       log.Println("No plugin for kind " + kind + " found. Using generic Plugin")
-                       return k.createGeneric(kind, files, namespace)
-               }
+       //Populate the namespace from profile instead of instance body
+       genericKubeData := &utils.ResourceData{
+               YamlFilePath: resTempl.FilePath,
+               Namespace:    namespace,
+       }
 
-               symCreateResourceFunc, err := typePlugin.Lookup("Create")
-               if err != nil {
-                       return nil, pkgerrors.Wrap(err, "Error fetching "+kind+" plugin")
-               }
+       typePlugin, ok := utils.LoadedPlugins[strings.ToLower(resTempl.GVK.Kind)]
+       if !ok {
+               log.Println("No plugin for kind " + resTempl.GVK.Kind + " found. Using generic Plugin")
+               return k.createGeneric(resTempl, namespace)
+       }
 
-               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)
+       symCreateResourceFunc, err := typePlugin.Lookup("Create")
+       if err != nil {
+               return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error fetching "+resTempl.GVK.Kind+" plugin")
        }
 
-       return resourcesCreated, nil
+       createdResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
+               genericKubeData, k.clientSet)
+       if err != nil {
+               return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error in plugin "+resTempl.GVK.Kind+" plugin")
+       }
+       log.Print(createdResourceName + " created")
+       return helm.KubernetesResource{
+               GVK:  resTempl.GVK,
+               Name: createdResourceName,
+       }, nil
 }
 
-func (k *KubernetesClient) createResources(resMap map[string][]string,
-       namespace string) (map[string][]string, error) {
+func (k *KubernetesClient) createResources(sortedTemplates []helm.KubernetesResourceTemplate,
+       namespace string) ([]helm.KubernetesResource, 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)
+       var createdResources []helm.KubernetesResource
+       for _, resTempl := range sortedTemplates {
+               resCreated, err := k.createKind(resTempl, namespace)
                if err != nil {
-                       return nil, pkgerrors.Wrap(err, "Error creating kind: "+kind)
+                       return nil, pkgerrors.Wrapf(err, "Error creating kind: %+v", resTempl.GVK)
                }
-
-               createdResourceMap[kind] = resourcesCreated
-               delete(resMap, kind)
+               createdResources = append(createdResources, resCreated)
        }
 
-       //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
+       return createdResources, nil
 }
 
-func (k *KubernetesClient) deleteGeneric(kind string, resources []string, namespace string) error {
-       log.Println("Deleting items of Kind: " + kind)
+func (k *KubernetesClient) deleteGeneric(resource helm.KubernetesResource, namespace string) error {
+       log.Println("Deleting Kind: " + resource.GVK.Kind)
 
        pluginObject, ok := utils.LoadedPlugins["generic"]
        if !ok {
                return pkgerrors.New("No generic plugin found")
        }
 
+       //Check if have the mapper before loading the plugin
+       err := k.updateMapper()
+       if err != nil {
+               return pkgerrors.Wrap(err, "Unable to create RESTMapper")
+       }
+
        symbol, err := pluginObject.Lookup("ExportedVariable")
        if err != nil {
                return pkgerrors.Wrap(err, "No ExportedVariable symbol found")
@@ -251,45 +234,42 @@ func (k *KubernetesClient) deleteGeneric(kind string, resources []string, namesp
                return pkgerrors.New("ExportedVariable is not PluginReference type")
        }
 
-       for _, res := range resources {
-               err = genericPlugin.Delete(kind, res, namespace, k)
-               if err != nil {
-                       return pkgerrors.Wrap(err, "Error in generic plugin")
-               }
+       err = genericPlugin.Delete(resource, namespace, k)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error in generic plugin")
        }
 
        return nil
 }
 
-func (k *KubernetesClient) deleteKind(kind string, resources []string, namespace string) error {
-       log.Println("Deleting items of Kind: " + kind)
+func (k *KubernetesClient) deleteKind(resource helm.KubernetesResource, namespace string) error {
+       log.Println("Deleting Kind: " + resource.GVK.Kind)
 
-       typePlugin, ok := utils.LoadedPlugins[strings.ToLower(kind)]
+       typePlugin, ok := utils.LoadedPlugins[strings.ToLower(resource.GVK.Kind)]
        if !ok {
-               log.Println("No plugin for kind " + kind + " found. Using generic Plugin")
-               return k.deleteGeneric(kind, resources, namespace)
+               log.Println("No plugin for kind " + resource.GVK.Kind + " found. Using generic Plugin")
+               return k.deleteGeneric(resource, namespace)
        }
 
        symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
        if err != nil {
-               return pkgerrors.Wrap(err, "Error findinf Delete symbol in plugin")
+               return pkgerrors.Wrap(err, "Error finding Delete symbol in 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)
-               }
+       log.Println("Deleting resource: " + resource.Name)
+       err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
+               resource.Name, namespace, k.clientSet)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error destroying "+resource.Name)
        }
+
        return nil
 }
 
-func (k *KubernetesClient) deleteResources(resMap map[string][]string, namespace string) error {
+func (k *KubernetesClient) deleteResources(resources []helm.KubernetesResource, namespace string) error {
        //TODO: Investigate if deletion should be in a particular order
-       for kind, resourceNames := range resMap {
-               err := k.deleteKind(kind, resourceNames, namespace)
+       for _, res := range resources {
+               err := k.deleteKind(res, namespace)
                if err != nil {
                        return pkgerrors.Wrap(err, "Deleting resources")
                }
index b343643..d023fcf 100644 (file)
@@ -20,8 +20,10 @@ import (
        "testing"
 
        utils "k8splugin/internal"
+       "k8splugin/internal/helm"
 
        pkgerrors "github.com/pkg/errors"
+       "k8s.io/apimachinery/pkg/runtime/schema"
        "k8s.io/client-go/kubernetes"
 )
 
@@ -76,9 +78,21 @@ func TestCreateResources(t *testing.T) {
        }
 
        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"},
+               data := []helm.KubernetesResourceTemplate{
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "apps",
+                                       Version: "v1",
+                                       Kind:    "Deployment"},
+                               FilePath: "../../mock_files/mock_yamls/deployment.yaml",
+                       },
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "",
+                                       Version: "v1",
+                                       Kind:    "Service"},
+                               FilePath: "../../mock_files/mock_yamls/service.yaml",
+                       },
                }
 
                _, err := k8.createResources(data, "testnamespace")
@@ -105,9 +119,35 @@ func TestDeleteResources(t *testing.T) {
        }
 
        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"},
+               data := []helm.KubernetesResource{
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "apps",
+                                       Version: "v1",
+                                       Kind:    "Deployment"},
+                               Name: "deployment-1",
+                       },
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "apps",
+                                       Version: "v1",
+                                       Kind:    "Deployment"},
+                               Name: "deployment-2",
+                       },
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "",
+                                       Version: "v1",
+                                       Kind:    "Service"},
+                               Name: "service-1",
+                       },
+                       {
+                               GVK: schema.GroupVersionKind{
+                                       Group:   "",
+                                       Version: "v1",
+                                       Kind:    "Service"},
+                               Name: "service-2",
+                       },
                }
 
                err := k8.deleteResources(data, "test")
index 93305c3..8e9a2b7 100644 (file)
@@ -23,6 +23,7 @@ import (
        "os"
 
        "k8splugin/internal/db"
+       "k8splugin/internal/helm"
        "k8splugin/internal/rb"
 
        pkgerrors "github.com/pkg/errors"
@@ -40,13 +41,13 @@ type InstanceRequest struct {
 
 // 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"`
+       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   []helm.KubernetesResource `json:"resources"`
 }
 
 // InstanceManager is an interface exposes the instantiation functionality
@@ -113,7 +114,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
        overrideValues := []string{}
 
        //Execute the kubernetes create command
-       resMap, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
+       sortedTemplates, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
        if err != nil {
                return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
        }
@@ -124,7 +125,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information")
        }
 
-       createdResources, err := k8sClient.createResources(resMap, profile.Namespace)
+       createdResources, err := k8sClient.createResources(sortedTemplates, profile.Namespace)
        if err != nil {
                return InstanceResponse{}, pkgerrors.Wrap(err, "Create Kubernetes Resources")
        }
index effd5c9..3828ed3 100644 (file)
@@ -21,7 +21,10 @@ import (
 
        utils "k8splugin/internal"
        "k8splugin/internal/db"
+       "k8splugin/internal/helm"
        "k8splugin/internal/rb"
+
+       "k8s.io/apimachinery/pkg/runtime/schema"
 )
 
 func TestInstanceCreate(t *testing.T) {
@@ -189,16 +192,32 @@ func TestInstanceGet(t *testing.T) {
                        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\"]" +
-                                                       "}}"),
+                                               `{
+                                                       "profile-name":"profile1",
+                                                       "id":"HaKpys8e",
+                                                       "namespace":"testnamespace",
+                                                       "rb-name":"test-rbdef",
+                                                       "rb-version":"v1",
+                                                       "cloud-region":"region1",
+                                                       "resources": [
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"apps",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Deployment"
+                                                                       },
+                                                                       "Name": "deployment-1"
+                                                               },
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Service"
+                                                                       },
+                                                                       "Name": "service-1"
+                                                               }
+                                                       ]
+                                               }`),
                                },
                        },
                }
@@ -210,16 +229,29 @@ func TestInstanceGet(t *testing.T) {
                        ProfileName: "profile1",
                        CloudRegion: "region1",
                        Namespace:   "testnamespace",
-                       Resources: map[string][]string{
-                               "deployment": []string{"test-deployment"},
-                               "service":    []string{"test-service"},
+
+                       Resources: []helm.KubernetesResource{
+                               {
+                                       GVK: schema.GroupVersionKind{
+                                               Group:   "apps",
+                                               Version: "v1",
+                                               Kind:    "Deployment"},
+                                       Name: "deployment-1",
+                               },
+                               {
+                                       GVK: schema.GroupVersionKind{
+                                               Group:   "",
+                                               Version: "v1",
+                                               Kind:    "Service"},
+                                       Name: "service-1",
+                               },
                        },
                }
                ic := NewInstanceClient()
                id := "HaKpys8e"
                data, err := ic.Get(id)
                if err != nil {
-                       t.Fatalf("TestInstanceDelete returned an error (%s)", err)
+                       t.Fatalf("TestInstanceGet returned an error (%s)", err)
                }
                if !reflect.DeepEqual(expected, data) {
                        t.Fatalf("TestInstanceGet returned:\n result=%v\n expected=%v",
@@ -232,16 +264,32 @@ func TestInstanceGet(t *testing.T) {
                        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\"]" +
-                                                       "}}"),
+                                               `{
+                                                       "profile-name":"profile1",
+                                                       "id":"HaKpys8e",
+                                                       "namespace":"testnamespace",
+                                                       "rb-name":"test-rbdef",
+                                                       "rb-version":"v1",
+                                                       "cloud-region":"region1",
+                                                       "resources": [
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"apps",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Deployment"
+                                                                       },
+                                                                       "Name": "deployment-1"
+                                                               },
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Service"
+                                                                       },
+                                                                       "Name": "service-1"
+                                                               }
+                                                       ]
+                                               }`),
                                },
                        },
                }
@@ -272,16 +320,32 @@ func TestInstanceDelete(t *testing.T) {
                        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\"]" +
-                                                       "}}"),
+                                               `{
+                                                       "profile-name":"profile1",
+                                                       "id":"HaKpys8e",
+                                                       "namespace":"testnamespace",
+                                                       "rb-name":"test-rbdef",
+                                                       "rb-version":"v1",
+                                                       "cloud-region":"mock_config",
+                                                       "resources": [
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"apps",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Deployment"
+                                                                       },
+                                                                       "Name": "deployment-1"
+                                                               },
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Service"
+                                                                       },
+                                                                       "Name": "service-1"
+                                                               }
+                                                       ]
+                                               }`),
                                },
                        },
                }
@@ -299,16 +363,32 @@ func TestInstanceDelete(t *testing.T) {
                        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\"]" +
-                                                       "}}"),
+                                               `{
+                                                       "profile-name":"profile1",
+                                                       "id":"HaKpys8e",
+                                                       "namespace":"testnamespace",
+                                                       "rb-name":"test-rbdef",
+                                                       "rb-version":"v1",
+                                                       "cloud-region":"mock_config",
+                                                       "resources": [
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"apps",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Deployment"
+                                                                       },
+                                                                       "Name": "deployment-1"
+                                                               },
+                                                               {
+                                                                       "GVK": {
+                                                                               "Group":"",
+                                                                               "Version":"v1",
+                                                                               "Kind":"Service"
+                                                                       },
+                                                                       "Name": "service-1"
+                                                               }
+                                                       ]
+                                               }`),
                                },
                        },
                }
index 65a36d6..1ab701a 100644 (file)
@@ -28,8 +28,10 @@ import (
 
        "github.com/ghodss/yaml"
        pkgerrors "github.com/pkg/errors"
-
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       "k8s.io/apimachinery/pkg/runtime/serializer/json"
        "k8s.io/apimachinery/pkg/util/validation"
+       k8syaml "k8s.io/apimachinery/pkg/util/yaml"
        "k8s.io/helm/pkg/chartutil"
        "k8s.io/helm/pkg/manifest"
        "k8s.io/helm/pkg/proto/hapi/chart"
@@ -143,10 +145,11 @@ func (h *TemplateClient) ensureDirectory(f string) error {
 }
 
 // GenerateKubernetesArtifacts a mapping of type to fully evaluated helm template
-func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFiles []string, values []string) (map[string][]string, error) {
+func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFiles []string,
+       values []string) ([]KubernetesResourceTemplate, error) {
 
        var outputDir, chartPath, namespace, releaseName string
-       var retData map[string][]string
+       var retData []KubernetesResourceTemplate
 
        releaseName = h.releaseName
        namespace = h.kubeNameSpace
@@ -226,7 +229,6 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
        var manifestsToRender []manifest.Manifest
        //render all manifests in the chart
        manifestsToRender = listManifests
-       retData = make(map[string][]string)
        for _, m := range tiller.SortByKind(manifestsToRender) {
                data := m.Content
                b := filepath.Base(m.Name)
@@ -249,11 +251,31 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
                        return retData, err
                }
 
-               if val, ok := retData[m.Head.Kind]; ok {
-                       retData[m.Head.Kind] = append(val, mfilePath)
-               } else {
-                       retData[m.Head.Kind] = []string{mfilePath}
+               gvk, err := getGroupVersionKind(data)
+               if err != nil {
+                       return retData, err
                }
+
+               kres := KubernetesResourceTemplate{
+                       GVK:      gvk,
+                       FilePath: mfilePath,
+               }
+               retData = append(retData, kres)
        }
        return retData, nil
 }
+
+func getGroupVersionKind(data string) (schema.GroupVersionKind, error) {
+       out, err := k8syaml.ToJSON([]byte(data))
+       if err != nil {
+               return schema.GroupVersionKind{}, pkgerrors.Wrap(err, "Converting yaml to json")
+       }
+
+       simpleMeta := json.SimpleMetaFactory{}
+       gvk, err := simpleMeta.Interpret(out)
+       if err != nil {
+               return schema.GroupVersionKind{}, pkgerrors.Wrap(err, "Parsing apiversion and kind")
+       }
+
+       return *gvk, nil
+}
index 27bb9d7..a13c67b 100644 (file)
@@ -165,27 +165,26 @@ func TestGenerateKubernetesArtifacts(t *testing.T) {
                        } else {
                                //Compute the hash of returned data and compare
                                for _, v := range out {
-                                       for _, f := range v {
-                                               data, err := ioutil.ReadFile(f)
-                                               if err != nil {
-                                                       t.Errorf("Unable to read file %s", v)
-                                               }
-                                               h.Write(data)
-                                               gotHash := fmt.Sprintf("%x", h.Sum(nil))
-                                               h.Reset()
+                                       f := v.FilePath
+                                       data, err := ioutil.ReadFile(f)
+                                       if err != nil {
+                                               t.Errorf("Unable to read file %s", v)
+                                       }
+                                       h.Write(data)
+                                       gotHash := fmt.Sprintf("%x", h.Sum(nil))
+                                       h.Reset()
 
-                                               //Find the right hash from expectedHashMap
-                                               expectedHash := ""
-                                               for k1, v1 := range testCase.expectedHashMap {
-                                                       if strings.Contains(f, k1) == true {
-                                                               expectedHash = v1
-                                                               break
-                                                       }
-                                               }
-                                               if gotHash != expectedHash {
-                                                       t.Fatalf("Got unexpected hash for %s", f)
+                                       //Find the right hash from expectedHashMap
+                                       expectedHash := ""
+                                       for k1, v1 := range testCase.expectedHashMap {
+                                               if strings.Contains(f, k1) == true {
+                                                       expectedHash = v1
+                                                       break
                                                }
                                        }
+                                       if gotHash != expectedHash {
+                                               t.Fatalf("Got unexpected hash for %s", f)
+                                       }
                                }
                        }
                })
diff --git a/src/k8splugin/internal/helm/types.go b/src/k8splugin/internal/helm/types.go
new file mode 100644 (file)
index 0000000..2c8badb
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 helm
+
+import (
+       "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// Represents the template that is used to create a particular
+// resource in Kubernetes
+type KubernetesResourceTemplate struct {
+       // Tracks the apiVersion and Kind of the resource
+       GVK schema.GroupVersionKind
+       // Path to the file that contains the resource info
+       FilePath string
+}
+
+// KubernetesResource is the resource that is created in Kubernetes
+// It is the type that will be used for tracking a resource.
+// Any future information such as status, time can be added here
+// for tracking.
+type KubernetesResource struct {
+       // Tracks the apiVersion and Kind of the resource
+       GVK schema.GroupVersionKind
+       // Name of resource in Kubernetes
+       Name string
+}
index b61fc49..e2fa5b3 100644 (file)
@@ -19,16 +19,16 @@ package rb
 import (
        "bytes"
        "encoding/json"
-       "k8splugin/internal/db"
-       "k8splugin/internal/helm"
+       "io/ioutil"
        "log"
+       "path/filepath"
        "strconv"
        "strings"
-
-       "io/ioutil"
-       "path/filepath"
        "sync"
 
+       "k8splugin/internal/db"
+       "k8splugin/internal/helm"
+
        "github.com/ghodss/yaml"
        pkgerrors "github.com/pkg/errors"
 )
@@ -56,9 +56,9 @@ type ConfigVersionStore struct {
 }
 
 type configResourceList struct {
-       retmap  map[string][]string
-       profile Profile
-       action  string
+       resourceTemplates []helm.KubernetesResourceTemplate
+       profile           Profile
+       action            string
 }
 
 type profileDataManager struct {
@@ -341,13 +341,13 @@ func scheduleResources(c chan configResourceList) {
                //TODO: ADD Check to see if Application running
                switch {
                case data.action == "POST":
-                       log.Printf("[scheduleResources]: POST %v %v", data.profile, data.retmap)
+                       log.Printf("[scheduleResources]: POST %v %v", data.profile, data.resourceTemplates)
                        //TODO: Needs to add code to call Kubectl create
                case data.action == "PUT":
-                       log.Printf("[scheduleResources]: PUT %v %v", data.profile, data.retmap)
+                       log.Printf("[scheduleResources]: PUT %v %v", data.profile, data.resourceTemplates)
                        //TODO: Needs to add code to call Kubectl apply
                case data.action == "DELETE":
-                       log.Printf("[scheduleResources]: DELETE %v %v", data.profile, data.retmap)
+                       log.Printf("[scheduleResources]: DELETE %v %v", data.profile, data.resourceTemplates)
                        //TODO: Needs to add code to call Kubectl delete
 
                }
@@ -358,7 +358,7 @@ func scheduleResources(c chan configResourceList) {
 //configuration overrides resides.
 var resolve = func(rbName, rbVersion, profileName string, p Config) (configResourceList, error) {
 
-       var retMap map[string][]string
+       var resTemplates []helm.KubernetesResourceTemplate
 
        profile, err := NewProfileClient().Get(rbName, rbVersion, profileName)
        if err != nil {
@@ -408,15 +408,15 @@ var resolve = func(rbName, rbVersion, profileName string, p Config) (configResou
                profile.ReleaseName)
 
        chartPath := filepath.Join(chartBasePath, t.ChartName)
-       retMap, err = helmClient.GenerateKubernetesArtifacts(chartPath,
+       resTemplates, err = helmClient.GenerateKubernetesArtifacts(chartPath,
                []string{outputfile.Name()},
                nil)
        if err != nil {
                return configResourceList{}, pkgerrors.Wrap(err, "Generate final k8s yaml")
        }
        crl := configResourceList{
-               retmap:  retMap,
-               profile: profile,
+               resourceTemplates: resTemplates,
+               profile:           profile,
        }
 
        return crl, nil
index 679815a..7d3902f 100644 (file)
@@ -20,12 +20,12 @@ import (
        "bytes"
        "encoding/base64"
        "encoding/json"
-       "k8splugin/internal/db"
        "path/filepath"
 
-       pkgerrors "github.com/pkg/errors"
-
+       "k8splugin/internal/db"
        "k8splugin/internal/helm"
+
+       pkgerrors "github.com/pkg/errors"
 )
 
 // Profile contains the parameters needed for resource bundle (rb) profiles
@@ -236,48 +236,48 @@ func (v *ProfileClient) Download(rbName, rbVersion, prName string) ([]byte, erro
 //Resolve returns the path where the helm chart merged with
 //configuration overrides resides.
 func (v *ProfileClient) Resolve(rbName string, rbVersion string,
-       profileName string, values []string) (map[string][]string, error) {
+       profileName string, values []string) ([]helm.KubernetesResourceTemplate, error) {
 
-       var retMap map[string][]string
+       var sortedTemplates []helm.KubernetesResourceTemplate
 
        //Download and process the profile first
        //If everything seems okay, then download the definition
        prData, err := v.Download(rbName, rbVersion, profileName)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Downloading Profile")
+               return sortedTemplates, pkgerrors.Wrap(err, "Downloading Profile")
        }
 
        prPath, err := ExtractTarBall(bytes.NewBuffer(prData))
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Extracting Profile Content")
+               return sortedTemplates, pkgerrors.Wrap(err, "Extracting Profile Content")
        }
 
        prYamlClient, err := ProcessProfileYaml(prPath, v.manifestName)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Processing Profile Manifest")
+               return sortedTemplates, pkgerrors.Wrap(err, "Processing Profile Manifest")
        }
 
        definitionClient := NewDefinitionClient()
 
        definition, err := definitionClient.Get(rbName, rbVersion)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Getting Definition Metadata")
+               return sortedTemplates, pkgerrors.Wrap(err, "Getting Definition Metadata")
        }
 
        defData, err := definitionClient.Download(rbName, rbVersion)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Downloading Definition")
+               return sortedTemplates, pkgerrors.Wrap(err, "Downloading Definition")
        }
 
        chartBasePath, err := ExtractTarBall(bytes.NewBuffer(defData))
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Extracting Definition Charts")
+               return sortedTemplates, 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")
+               return sortedTemplates, pkgerrors.Wrap(err, "Getting Profile")
        }
 
        //Copy the profile configresources to the chart locations
@@ -287,7 +287,7 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
        //   chartpath: chart/config/resources/config.yaml
        err = prYamlClient.CopyConfigurationOverrides(chartBasePath)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Copying configresources to chart")
+               return sortedTemplates, pkgerrors.Wrap(err, "Copying configresources to chart")
        }
 
        helmClient := helm.NewTemplateClient(profile.KubernetesVersion,
@@ -295,12 +295,12 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
                profile.ReleaseName)
 
        chartPath := filepath.Join(chartBasePath, definition.ChartName)
-       retMap, err = helmClient.GenerateKubernetesArtifacts(chartPath,
+       sortedTemplates, err = helmClient.GenerateKubernetesArtifacts(chartPath,
                []string{prYamlClient.GetValues()},
                values)
        if err != nil {
-               return retMap, pkgerrors.Wrap(err, "Generate final k8s yaml")
+               return sortedTemplates, pkgerrors.Wrap(err, "Generate final k8s yaml")
        }
 
-       return retMap, nil
+       return sortedTemplates, nil
 }
index b0cf609..9073535 100644 (file)
@@ -24,22 +24,12 @@ import (
 
        utils "k8splugin/internal"
        "k8splugin/internal/app"
+       "k8splugin/internal/helm"
 )
 
 type genericPlugin struct {
 }
 
-var kindToGVRMap = map[string]schema.GroupVersionResource{
-       "ConfigMap":   schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"},
-       "StatefulSet": schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"},
-       "Job":         schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"},
-       "Pod":         schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
-       "DaemonSet":   schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"},
-       "CustomResourceDefinition": schema.GroupVersionResource{
-               Group: "apiextensions.k8s.io", Version: "v1beta1", Resource: "customresourcedefinitions",
-       },
-}
-
 // Create deployment object in a specific Kubernetes cluster
 func (g genericPlugin) Create(yamlFilePath string, namespace string, client *app.KubernetesClient) (string, error) {
        if namespace == "" {
@@ -79,7 +69,7 @@ func (g genericPlugin) Create(yamlFilePath string, namespace string, client *app
 }
 
 // Delete an existing deployment hosted in a specific Kubernetes cluster
-func (g genericPlugin) Delete(kind string, name string, namespace string, client *app.KubernetesClient) error {
+func (g genericPlugin) Delete(resource helm.KubernetesResource, namespace string, client *app.KubernetesClient) error {
        if namespace == "" {
                namespace = "default"
        }
@@ -90,14 +80,20 @@ func (g genericPlugin) Delete(kind string, name string, namespace string, client
        }
 
        dynClient := client.GetDynamicClient()
-       gvr, ok := kindToGVRMap[kind]
-       if !ok {
-               return pkgerrors.New("GVR not found for: " + kind)
+       mapper := client.GetMapper()
+
+       mapping, err := mapper.RESTMapping(schema.GroupKind{
+               Group: resource.GVK.Group,
+               Kind:  resource.GVK.Kind,
+       }, resource.GVK.Version)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Mapping kind to resource error")
        }
 
+       gvr := mapping.Resource
        log.Printf("Using gvr: %s, %s, %s", gvr.Group, gvr.Version, gvr.Resource)
 
-       err := dynClient.Resource(gvr).Namespace(namespace).Delete(name, opts)
+       err = dynClient.Resource(gvr).Namespace(namespace).Delete(resource.Name, opts)
        if err != nil {
                return pkgerrors.Wrap(err, "Delete object error")
        }