aboutsummaryrefslogtreecommitdiffstats
path: root/src/k8splugin/internal/app
diff options
context:
space:
mode:
authorKiran Kamineni <kiran.k.kamineni@intel.com>2019-04-16 18:09:13 -0700
committerKiran Kamineni <kiran.k.kamineni@intel.com>2019-04-16 18:09:27 -0700
commitbf49d552b003072c6bc64ae838a4699c1f4028bd (patch)
tree57c2b6130781f8215b0544e6b6f126ec8e2f8152 /src/k8splugin/internal/app
parent244578803033f17781b10be283aef43fa6f0aa60 (diff)
Replace Kind with GroupVersionKind
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>
Diffstat (limited to 'src/k8splugin/internal/app')
-rw-r--r--src/k8splugin/internal/app/client.go190
-rw-r--r--src/k8splugin/internal/app/client_test.go52
-rw-r--r--src/k8splugin/internal/app/instance.go19
-rw-r--r--src/k8splugin/internal/app/instance_test.go168
4 files changed, 265 insertions, 164 deletions
diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go
index 9b8873cc..7024420c 100644
--- a/src/k8splugin/internal/app/client.go
+++ b/src/k8splugin/internal/app/client.go
@@ -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")
}
diff --git a/src/k8splugin/internal/app/client_test.go b/src/k8splugin/internal/app/client_test.go
index b3436431..d023fcff 100644
--- a/src/k8splugin/internal/app/client_test.go
+++ b/src/k8splugin/internal/app/client_test.go
@@ -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")
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
index 93305c30..8e9a2b7a 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -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")
}
diff --git a/src/k8splugin/internal/app/instance_test.go b/src/k8splugin/internal/app/instance_test.go
index effd5c99..3828ed38 100644
--- a/src/k8splugin/internal/app/instance_test.go
+++ b/src/k8splugin/internal/app/instance_test.go
@@ -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"
+ }
+ ]
+ }`),
},
},
}