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() {
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
}
|