package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	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/schema"
	syaml "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
	"k8s.io/apimachinery/pkg/types"
	"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"

	restclient "k8s.io/client-go/rest"

	sigyaml "sigs.k8s.io/yaml"

)
var s = `
apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: sentry-project
    meta.helm.sh/release-namespace: helm-sentry
  labels:
    app: sentry-project
    app.kubernetes.io/managed-by: Helm
    heritage: Helm
    release: sentry-project
  name: sentry-project-web
  #namespace: helm-sentry
spec:
  ports:
  - name: sentry
    port: 9000
    protocol: TCP
    targetPort: 9000
  selector:
    app: sentry-project
    role: web
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: sentry-project
    meta.helm.sh/release-namespace: helm-sentry
  labels:
    app: sentry-project
    app.kubernetes.io/managed-by: Helm
    chart: sentry-12.0.0
    heritage: Helm
    release: sentry-project
  name: sentry-project-relay
spec:
  ports:
  - name: sentry-relay
    port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: sentry-project
    role: relay
  type: ClusterIP
`

var (
	config    *restclient.Config
	clientSet *kubernetes.Clientset
	dynameicclient dynamic.Interface
)

type ApplyYaml struct {
	applyYaml string
	namespace string
	applyErr map[string]error
}


func init() {
	var err error
	config, err = clientcmd.BuildConfigFromFlags("", "/Users/qushuaibo/.kube/config")
	if err != nil {
		panic(err)
	}

	clientSet ,err = kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	dynameicclient,err  = dynamic.NewForConfig(config)
	if err != nil {
		panic(err)
	}
}


func NewApplyYaml(y ,ns string) *ApplyYaml {
	return &ApplyYaml{
		applyYaml: s,
		namespace: ns,
		applyErr: map[string]error{},
	}
}

func main() {
	apply := NewApplyYaml(s,"default")
	apply.CreateOrUpdateFromYaml()
	for k,v := range apply.applyErr {
		fmt.Println(k,v)
	}
}


func (y *ApplyYaml) CreateOrUpdateFromYaml()  {
	//序列化为yaml
	d := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(y.applyYaml), 4096)

	for {

		var (
			rawObj runtime.RawExtension
		)

		err := d.Decode(&rawObj)
		if err == io.EOF {
			break
		}
		if err != nil {
			y.applyErr["decode"] = fmt.Errorf("decode is err %v", err)
			continue
		}

		obj, _, err := syaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil)
		if err != nil {
			y.applyErr["decode"] =  fmt.Errorf("rawobj is err%v", err)
			continue
		}

		unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
		if err != nil {
			y.applyErr["decode"] = fmt.Errorf("tounstructured is err %v", err)
			continue
		}

		unstructureObj := &unstructured.Unstructured{Object: unstructuredMap}
		gvr, err := y.GtGVR(unstructureObj.GroupVersionKind())
		if err != nil {
			y.applyErr[unstructureObj.GetName()] = fmt.Errorf("get gvr is false %v",err)
			continue
		}

		unstructuredYaml, err := sigyaml.Marshal(unstructureObj)
		if err != nil {
			y.applyErr[unstructureObj.GetName()] =  fmt.Errorf("unable to marshal resource as yaml: %w", err)
			continue
		}

		if y.namespace != "" && unstructureObj.GetNamespace() != "" &&  y.namespace != unstructureObj.GetNamespace(){
			y.applyErr[unstructureObj.GetName()] = fmt.Errorf("the namespace from the provided object %v does not match the namespace %v",y.namespace,unstructureObj.GetNamespace())
			continue
		}


		if y.namespace == "" && unstructureObj.GetNamespace() ==  "" {
			unstructureObj.SetNamespace("default" )
		}


		_, err = dynameicclient.Resource(gvr).Namespace(y.namespace).Get(context.Background(), unstructureObj.GetName(), metav1.GetOptions{})
		if err != nil {
			_, createErr := dynameicclient.Resource(gvr).Namespace(y.namespace).Create(context.Background(), unstructureObj, metav1.CreateOptions{})
			if createErr != nil {
				y.applyErr[unstructureObj.GetName()] = fmt.Errorf("create err is :%v",createErr)
				continue
			}
			fmt.Printf("create %v   %v \n",unstructureObj.GetKind(),unstructureObj.GetName())
			continue
		}

		force := true

		_, err = dynameicclient.Resource(gvr).
			Namespace(unstructureObj.GetNamespace()).
			Patch(context.Background(),
				unstructureObj.GetName(),
				types.ApplyPatchType,
				unstructuredYaml, metav1.PatchOptions{
					FieldManager: unstructureObj.GetName(),
					Force:        &force,
				})


		if err != nil {
			y.applyErr[unstructureObj.GetName()] = fmt.Errorf("unable to patch resource: %w", err)
			continue
		}
	}

	return
}


func (y *ApplyYaml) GtGVR(gvk schema.GroupVersionKind) (schema.GroupVersionResource, error) {

	gr, err := restmapper.GetAPIGroupResources(clientSet)
	if err != nil {
		return schema.GroupVersionResource{}, err
	}

	mapper := restmapper.NewDiscoveryRESTMapper(gr)

	mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
	if err != nil {
		return schema.GroupVersionResource{}, err
	}

	return mapping.Resource, nil
}
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐