Search code examples
gokubernetescontrollerkubectl

the equivalent way of doing 'kubectl apply' in Golang


It's simple to apply complicate yaml config using kubectl, for example, installing the kong-ingress-controller is simply one line using kubectl:

kubectl apply -f https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-dbless.yaml

what is the equivalent way of doing this in Golang?


Solution

  • figured out by checking out this issue: https://github.com/kubernetes/client-go/issues/193#issuecomment-363318588

    I'm using kubebuilder, simple turn yamls into runtime.Objects using UniversalDeserializer, then create the object using Reconciler's Create method:

    // ref: https://github.com/kubernetes/client-go/issues/193#issuecomment-363318588
    func parseK8sYaml(fileR []byte) []runtime.Object {
    
        acceptedK8sTypes := regexp.MustCompile(`(Namespace|Role|ClusterRole|RoleBinding|ClusterRoleBinding|ServiceAccount)`)
        fileAsString := string(fileR[:])
        sepYamlfiles := strings.Split(fileAsString, "---")
        retVal := make([]runtime.Object, 0, len(sepYamlfiles))
        for _, f := range sepYamlfiles {
            if f == "\n" || f == "" {
                // ignore empty cases
                continue
            }
    
            decode := scheme.Codecs.UniversalDeserializer().Decode
            obj, groupVersionKind, err := decode([]byte(f), nil, nil)
    
            if err != nil {
                log.Println(fmt.Sprintf("Error while decoding YAML object. Err was: %s", err))
                continue
            }
    
            if !acceptedK8sTypes.MatchString(groupVersionKind.Kind) {
                log.Printf("The custom-roles configMap contained K8s object types which are not supported! Skipping object with type: %s", groupVersionKind.Kind)
            } else {
                retVal = append(retVal, obj)
            }
    
        }
        return retVal
    }
    
    func (r *MyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
        ctx := context.Background()
        log := r.Log.WithValues("MyReconciler", req.NamespacedName)
    
        // your logic here
        log.Info("reconciling")
    
        yaml := `
    apiVersion: v1
    kind: Namespace
    metadata:
      name: test-ns`
        obj := parseK8sYaml([]byte(yaml))
        if err := r.Create(ctx, obj[0]); err != nil {
            log.Error(err, "failed when creating obj")
        }
    
        ...
    
    }