Skip to content

Instantly share code, notes, and snippets.

@pytimer
Created August 19, 2020 08:34
Show Gist options
  • Save pytimer/0ad436972a073bb37b8b6b8b474520fc to your computer and use it in GitHub Desktop.
Save pytimer/0ad436972a073bb37b8b6b8b474520fc to your computer and use it in GitHub Desktop.

Parse the kubernetes manifest in yaml or json, don't care a manifest type.

Examples:

package main

import (
	"bytes"
	"context"
	"flag"
	"io"
	"io/ioutil"
	"log"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
	yamlutil "k8s.io/apimachinery/pkg/util/yaml"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/restmapper"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	kubeconfig string
	filename   string
)

func main() {
	flag.StringVar(&kubeconfig, "kubeconfig", "", "")
	flag.StringVar(&filename, "f", "", "")
	flag.Parse()

	b, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("%q \n", string(b))

	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		log.Fatal(err)
	}

	c, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Fatal(err)
	}

	dd, err := dynamic.NewForConfig(config)
	if err != nil {
		log.Fatal(err)
	}

	decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader(b), 100)
	for {
		var rawObj runtime.RawExtension
		if err = decoder.Decode(&rawObj); err != nil {
			break
		}

		obj, gvk, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil)
		unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
		if err != nil {
			log.Fatal(err)
		}

		unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap}

		gr, err := restmapper.GetAPIGroupResources(c.Discovery())
		if err != nil {
			log.Fatal(err)
		}

		mapper := restmapper.NewDiscoveryRESTMapper(gr)
		mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
		if err != nil {
			log.Fatal(err)
		}

		var dri dynamic.ResourceInterface
		if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
			if unstructuredObj.GetNamespace() == "" {
				unstructuredObj.SetNamespace("default")
			}
			dri = dd.Resource(mapping.Resource).Namespace(unstructuredObj.GetNamespace())
		} else {
			dri = dd.Resource(mapping.Resource)
		}

		if _, err := dri.Create(context.Background(), unstructuredObj, metav1.CreateOptions{}); err != nil {
			log.Fatal(err)
		}
	}
	if err != io.EOF {
		log.Fatal("eof ", err)
	}
}

Usage:

app.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: demo
  name: demo
  namespace: default
spec:
  ports:
  - name: web
    port: 80
  selector:
    app: demo
  type: ClusterIP

go run demo.go -kubeconfig ~/.kube/config -f app.yaml

@ankitkapoord76
Copy link

ankitkapoord76 commented Apr 6, 2023

This code only work when the resource can not exist in k8s. So add https://github.com/pytimer/k8sutil/tree/main/examples/apply example, it like kubectl apply, support server-side and non server-side.

Thanks @pytimer for sharing the code.
I was able to apply YAML using this, but when I re-tried again, it reported error that the resource already exists, even though I deleted it manually. Does it cache somewhere? I thought it would update it even if it is there. Could you please share the complete code as well incorporating the update part? or, let me know how to do it. That’s why it ‘d be great if you could also elaborate this comment. Thanks in advance!

@ofey404
Copy link

ofey404 commented Jul 5, 2023

Thank you!

@piyushdatazip
Copy link

Thanks @pytimer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment