Skip to content

Commit

Permalink
Add support for applying and deleting configs on cluster
Browse files Browse the repository at this point in the history
This commit is to add support to apply generated configs on cluster and
then also enable users to delete them from cluster.
  • Loading branch information
YolandaDu1997 committed Jul 7, 2020
1 parent 9c0c66b commit 02d69aa
Show file tree
Hide file tree
Showing 2 changed files with 291 additions and 0 deletions.
86 changes: 86 additions & 0 deletions generators/pkg/manager/manage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package manager

import (
"context"
"flag"
"fmt"
"io"
"path/filepath"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"sigs.k8s.io/controller-runtime/pkg/client"

//"sigs.k8s.io/yaml"
"k8s.io/apimachinery/pkg/util/yaml"
)

// Create the Kubernetes client
func GetKubeClient() (client.Client, error) {
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()

// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
return nil, fmt.Errorf("fail to build config from the flags: %w", err)
}

return client.New(config, client.Options{})
}

func read(reader io.Reader) ([]*unstructured.Unstructured, error) {
//read the input file
r := yaml.NewYAMLToJSONDecoder(reader)
list := []*unstructured.Unstructured{}
for {
//unmarshal the yaml object
u := new(unstructured.Unstructured)
if err := r.Decode(u); err != nil {
if err == io.EOF {
return list, nil
}
return list, fmt.Errorf("failed to unmarshal the reader: %w", err)
}
//setup the namespace to default
if u.GetNamespace() == "" {
u.SetNamespace("default")
}
list = append(list, u)
}
}

// Create resources from io.Reader on Kubernetes objects using client
func CreateResource(cl client.Writer, reader io.Reader) error {
resources, err := read(reader)
if err != nil {
return fmt.Errorf("fail to read the resources: %w", err)
}
for _, r := range resources {
if err := cl.Create(context.Background(), r); err != nil {
return fmt.Errorf("failed to create the resource: %w", err)
}
}
return nil
}

// Delete resources from io.Reader on Kubernetes objects using client
func DeleteResource(cl client.Writer, reader io.Reader) error {
resources, err := read(reader)
if err != nil {
return fmt.Errorf("fail to read the resources: %w", err)
}
for _, r := range resources {
if err := cl.Delete(context.Background(), r); err != nil {
return fmt.Errorf("failed to delete the resource: %w", err)
}
}
return nil
}
205 changes: 205 additions & 0 deletions generators/pkg/manager/manage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package manager

import (
"bytes"
"context"
"testing"

"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)

type testClient struct {
client.Writer
list []runtime.Object
}

func (t *testClient) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error {
t.list = append(t.list, obj)
return nil
}

func (t *testClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error {
t.list = append(t.list, obj)
return nil
}

// testdata
var resources = []*unstructured.Unstructured{
{
Object: map[string]interface{}{
"name": "test-task",
"kind": "Task",
"apiVersion": "tekton.dev/v1beta1",
},
},

{
Object: map[string]interface{}{
"name": "test-task",
"kind": "Task",
"apiVersion": "tekton.dev/v1beta1",
"metadata": map[string]interface{}{
"namespace": "default",
},
},
},

{
Object: map[string]interface{}{
"name": "test-task",
"kind": "Task",
"apiVersion": "tekton.dev/v1beta1",
"metadata": map[string]interface{}{
"namespace": "default",
},
},
},

{
Object: map[string]interface{}{
"apiVersion": "tekton.dev/v1beta1",
"kind": "Task",
"metadata": map[string]interface{}{
"namespace": "default",
"name": "echo-hello-world",
},
"spec": map[string]interface{}{
"steps": map[string]interface{}{
"name": "echo",
"image": "ubuntu",
"command": []interface{}{string("echo")},
"args": []interface{}{string("Hello world")},
},
},
},
},
}

func TestApplyResource(t *testing.T) {
tables := []struct {
u *unstructured.Unstructured
want []runtime.Object
}{
{
resources[0],
[]runtime.Object{
&unstructured.Unstructured{
Object: map[string]interface{}{
"name": "test-task",
"kind": "Task",
"apiVersion": "tekton.dev/v1beta1",
"metadata": map[string]interface{}{
"namespace": "default",
},
},
},
},
},

{
resources[1],
[]runtime.Object{
resources[1],
},
},

{
resources[2],
[]runtime.Object{
resources[2],
},
},

{
resources[3],
[]runtime.Object{
resources[3],
},
},
}

for _, table := range tables {
b, err := yaml.Marshal(table.u)
if err != nil {
t.Fatalf("fail to marshal the test data: %v", err)
}

buf := bytes.NewBuffer(b)
client := &testClient{}
if err := CreateResource(client, buf); err != nil {
t.Fatalf("fail to create resource: %v", err)
}

if diff := cmp.Diff(table.want, client.list); diff != "" {
t.Errorf("Objects mismatch (-want +got): \n %s", diff)
}

}

}

func TestDeleteResource(t *testing.T) {
tables := []struct {
u *unstructured.Unstructured
want []runtime.Object
}{
{
resources[0],
[]runtime.Object{
&unstructured.Unstructured{
Object: map[string]interface{}{
"name": "test-task",
"kind": "Task",
"apiVersion": "tekton.dev/v1beta1",
"metadata": map[string]interface{}{
"namespace": "default",
},
},
},
},
},

{
resources[1],
[]runtime.Object{
resources[1],
},
},

{
resources[2],
[]runtime.Object{
resources[2],
},
},

{
resources[3],
[]runtime.Object{
resources[3],
},
},
}

for _, table := range tables {
b, err := yaml.Marshal(table.u)
if err != nil {
t.Fatalf("fail to marshal the test data: %v", err)
}

buf := bytes.NewBuffer(b)
client := &testClient{}
if err := DeleteResource(client, buf); err != nil {
t.Fatalf("fail to delete resource: %v", err)
}

if diff := cmp.Diff(table.want, client.list); diff != "" {
t.Errorf("Objects mismatch (-want +got): \n %s", diff)
}

}
}

0 comments on commit 02d69aa

Please sign in to comment.