Skip to content

Commit

Permalink
run plugin just once, only add resources to label if kubectl apply/cr…
Browse files Browse the repository at this point in the history
…eate/replace is run - might be other cases, fixed issue with objectcreation for ocm manifestwork and bindingpolicy
  • Loading branch information
clubanderson committed Apr 18, 2024
1 parent 027ffbc commit fe33ea7
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 75 deletions.
89 changes: 43 additions & 46 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -25,7 +24,7 @@ import (
"k8s.io/client-go/rest"
)

var Version = "0.18.1"
var Version = "0.18.2"

// Plugin interface
type Plugin interface {
Expand Down Expand Up @@ -165,22 +164,7 @@ func expandTilde(args []string) []string {
return args
}

func (p ParamsStruct) CreateObjForPlugin(gvk schema.GroupVersionKind, yamlData []byte, objName, objResource, namespace string) {
// Unmarshal YAML data into a map
var objMap map[string]interface{}
err := yaml.Unmarshal([]byte(yamlData), &objMap)
if err != nil {
fmt.Println("Error unmarshaling YAML:", err)
return
}

// Marshal the map into JSON
objectJSON, err := json.Marshal(objMap)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return
}

func (p ParamsStruct) CreateObjForPlugin(gvk schema.GroupVersionKind, yamlData []byte, objName, objResource, namespace string, objectJSON []byte) {
gvr := schema.GroupVersionResource{
Group: gvk.Group,
Version: gvk.Version,
Expand All @@ -193,44 +177,54 @@ func (p ParamsStruct) CreateObjForPlugin(gvk schema.GroupVersionKind, yamlData [
Resource: "namespaces",
}

if p.Flags["debug"] {
if p.Flags["l-debug"] {
log.Printf(" ℹ️ object info %v/%v/%v %v\n", nsgvr.Group, nsgvr.Version, nsgvr.Resource, namespace)
}
_, err = p.GetObject(p.DynamicClient, "", nsgvr, namespace)

_, err := p.createObject(p.DynamicClient, namespace, gvr, objectJSON)
if err != nil {
log.Printf(" 🔴 failed to create %v %q, namespace %q does not exist. Is KubeStellar installed?\n", objResource, objName, namespace)
} else {
_, err = p.createObject(p.DynamicClient, namespace, gvr, objectJSON)
if err != nil {
log.Printf(" 🔴 failed to create %v object %q in namespace %v. Is KubeStellar installed?\n", objResource, objName, namespace)
}
log.Printf(" 🔴 failed to create %v object %q in namespace %q: %v. Check if %q CRD is missing from cluster.\n", objResource, objName, namespace, err, objResource)
}
}

func (p ParamsStruct) createObject(ocDynamicClientCoreOrWds dynamic.Interface, namespace string, gvr schema.GroupVersionResource, objectJSON []byte) (string, error) {
objToCreate := &unstructured.Unstructured{}
var objMap map[string]interface{}
err := json.Unmarshal(objectJSON, &objMap)
if err != nil {
fmt.Println("Error unmarshaling JSON:", err)
return namespace, err
}

// printUnstructured(objToCreate)
// Create an unstructured.Unstructured object from the map
objToCreate := &unstructured.Unstructured{Object: objMap}

// unmarshal the JSON data into the Unstructured object
err := objToCreate.UnmarshalJSON(objectJSON)
if err != nil {
log.Printf("%v\n", err)
return namespace, nil
// Now objToCreate is an unstructured.Unstructured object representing the JSON data
// log.Printf("objToCreate: %v\n", objToCreate)
metadata, ok, _ := unstructured.NestedMap(objToCreate.Object, "Metadata")
if !ok {
fmt.Println("Metadata section not found")
return namespace, err
}
name, ok, _ := unstructured.NestedString(metadata, "Name")
if !ok {
fmt.Println("Name not found")
return namespace, err
}

// log.Printf("name: %v\n", name)

_, err = p.GetObject(ocDynamicClientCoreOrWds, namespace, gvr, objToCreate.GetName())
_, err = p.GetObject(ocDynamicClientCoreOrWds, namespace, gvr, name)
if err == nil {
// object still exists, can't create
if p.Flags["debug"] {
log.Printf(" ℹ️ object exists %v/%v/%v %v\n", gvr.Group, gvr.Version, gvr.Resource, objToCreate.GetName())
if p.Flags["l-debug"] {
log.Printf(" ℹ️ object exists %v/%v/%v %v\n", gvr.Group, gvr.Version, gvr.Resource, name)
}
return namespace, err
}

// log.Printf(" ℹ️ object info %v/%v/%v %v\n", gvr.Group, gvr.Version, gvr.Resource, objToCreate.GetName())
if errors.IsNotFound(err) {
retryCount := 10
retryCount := 3
for attempt := 1; attempt <= retryCount; attempt++ {
if namespace == "" {
_, err = ocDynamicClientCoreOrWds.Resource(gvr).Create(context.TODO(), objToCreate, metav1.CreateOptions{})
Expand All @@ -241,14 +235,14 @@ func (p ParamsStruct) createObject(ocDynamicClientCoreOrWds dynamic.Interface, n
if err == nil {
break
}
if p.Flags["debug"] {
if p.Flags["l-debug"] {
log.Printf(" ℹ️ object %s is being created (if error, namespace might be missing from resource definition). Retrying in 5 seconds: %v/%v/%v: %v\n", objToCreate.GetName(), gvr.Group, gvr.Version, gvr.Resource, err)
}
time.Sleep(5 * time.Second)
continue
}

if p.Flags["debug"] {
if p.Flags["l-debug"] {
if err != nil {
if namespace == "" {
log.Printf(" 🟡 error creating object %v/%v/%v %v: %v\n", gvr.Group, gvr.Version, gvr.Resource, objToCreate.GetName(), err)
Expand Down Expand Up @@ -304,16 +298,19 @@ func (p ParamsStruct) GetObject(ocDynamicClientCoreOrWds dynamic.Interface, name
return nil, errMarshal
}

if p.Flags["debug"] {
if err != nil {
// log.Printf(" > object not found %v/%v/%v %v in %q: %v\n", gvr.Group, gvr.Version, gvr.Resource, objectName, namespace, err)
return nil, err
if err != nil {
if p.Flags["l-debug"] {
log.Printf(" > object not found %v/%v/%v %q in %q: %v\n", gvr.Group, gvr.Version, gvr.Resource, objectName, namespace, err)
}
return nil, err

} else {
// log.Printf(" > found object %v/%v/%v %v in %q\n", gvr.Group, gvr.Version, gvr.Resource, objectName, namespace)
return objectJSON, nil
} else {
if p.Flags["l-debug"] {
log.Printf(" > found object %v/%v/%v %q in %q\n", gvr.Group, gvr.Version, gvr.Resource, objectName, namespace)
}
return objectJSON, nil
}

if err != nil {
return nil, err
}
Expand Down
21 changes: 11 additions & 10 deletions pkg/helpers/labeler-helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,12 @@ func AliasRun(args []string, p c.ParamsStruct) error {
strings.HasPrefix(arg, "expose") ||
strings.HasPrefix(arg, "autoscale") ||
strings.HasPrefix(arg, "attach") ||
strings.HasPrefix(arg, "exec") ||
strings.HasPrefix(arg, "wait") ||
strings.HasPrefix(arg, "cp") ||
strings.HasPrefix(arg, "run") ||
strings.HasPrefix(arg, "label") ||
strings.HasPrefix(arg, "annotate") ||
strings.HasPrefix(arg, "patch") ||
strings.HasPrefix(arg, "delete") ||
strings.HasPrefix(arg, "create") ||
strings.HasPrefix(arg, "replace") ||
strings.HasPrefix(arg, "edit") {
strings.HasPrefix(arg, "patch") {
p.Flags[arg] = true
}
}
Expand Down Expand Up @@ -239,22 +234,26 @@ func AliasRun(args []string, p c.ParamsStruct) error {

fnArgs := []reflect.Value{reflect.ValueOf(p), reflect.ValueOf(false)}

runOnce := make(map[string]bool)
for key := range combinedFlagsAndParams {
for pkey, value := range p.PluginArgs {
for _, vCSV := range value {
v := strings.Split(vCSV, ",")
if key == v[0] {
if p.PluginPtrs[pkey].IsValid() {
log.Printf("\nlabeler plugin: %q:\n\n", pkey)
p.PluginPtrs[pkey].Call(fnArgs)
if !runOnce[pkey] {
log.Printf("\nlabeler plugin: %q:\n\n", pkey)
p.PluginPtrs[pkey].Call(fnArgs)
runOnce[pkey] = true
}
}
}
}
}
}
if p.Flags["l-debug"] {
for key, value := range p.Resources {
fmt.Printf("labeler.go: [debug] resources: Key: %s, Value: %s\n", key, value)
fmt.Printf("labeler.go: [debug] resources: Key: %s, Value: \n%s\n", key, value)
}
}
}
Expand Down Expand Up @@ -337,7 +336,9 @@ func traverseKubectlOutput(input []string, p c.ParamsStruct) {
Namespace: namespace,
ObjectName: objectName,
}
addObjectsToResourcesAfterKubectlApply(resource, p)
if p.Flags["apply"] || p.Flags["create"] || p.Flags["replace"] {
addObjectsToResourcesAfterKubectlApply(resource, p)
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions pkg/plugin-bp-creator/plugin-bp-creator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pluginBPcreator

import (
"encoding/json"
"fmt"
"log"
"strings"
Expand Down Expand Up @@ -113,8 +114,13 @@ func PluginCreateBP(p c.ParamsStruct, reflect bool) []string {
}

if p.Params["l-bp-wds"] != "" {
log.Printf(" 🚀 Attempting to create %v object %q in WDS namespace %q", k, n, p.Params[nsArg])
p.CreateObjForPlugin(gvk, yamlData, n, r, p.Params["namespaceArg"])
log.Printf(" 🚀 Attempting to create %v object %q in WDS %q", k, n, p.Params["l-bp-wds"])
objectJSON, err := json.Marshal(bindingPolicy)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return []string{}
}
p.CreateObjForPlugin(gvk, yamlData, n, r, p.Params["l-bp-wds"], objectJSON)
} else {
fmt.Printf("%v", string(yamlData))
}
Expand Down
37 changes: 23 additions & 14 deletions pkg/plugin-ocm-creator/plugin-ocm-creator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pluginOCMcreator

import (
"encoding/json"
"fmt"
"log"

Expand All @@ -17,30 +18,31 @@ type ManifestWork struct {
Spec mwSpec `yaml:"spec"`
}

type mwSpec struct {
Workload Workload `yaml:"workload"`
}

type mwMetadata struct {
Name string `yaml:"name"`
}

type mwSpec struct {
Workload Workload `yaml:"workload"`
}

type Workload struct {
Manifests []map[string]interface{} `yaml:"manifests"`
}

type Manifest struct {
YAML string `yaml:"-"`
}
// Remove the unused type declaration
// type manifest struct {
// YAML string `yaml:"-"`
// }

func PluginCreateMW(p c.ParamsStruct, reflect bool) []string {
// function must be exportable (capitalize first letter of function name) to be discovered by labeler
if reflect {
return []string{"l-mw-name,string,name for the manifestwork object", "l-mw-create,flag,create/apply the manifestwork object"}
}
type PluginFunction struct {
pluginCreateMW string `triggerKey:"l-mw"`
}
// type PluginFunction struct {
// pluginCreateMW string `triggerKey:"l-mw"`
// }
n := "change-me"
nArg := "l-mw-name"
g := "work.open-cluster-management.io"
Expand Down Expand Up @@ -70,11 +72,10 @@ func PluginCreateMW(p c.ParamsStruct, reflect bool) []string {
},
},
}
// need a loop to fill in the manifests with the objects from debug run of kubectl or helm

for _, yamlData := range p.Resources {
for _, workloadYamlData := range p.Resources {
var obj map[string]interface{}
err := yaml.Unmarshal(yamlData, &obj)
err := yaml.Unmarshal(workloadYamlData, &obj)
if err != nil {
log.Printf("Error unmarshaling YAML: %v", err)
continue
Expand All @@ -87,10 +88,18 @@ func PluginCreateMW(p c.ParamsStruct, reflect bool) []string {
fmt.Println("Error marshaling YAML:", err)
return []string{}
}
// log.Printf("yamlData: \n%v", string(yamlData))

if p.Flags["l-mw-create"] {
log.Printf(" 🚀 Attempting to create %v object %q in namespace %q", k, n, p.Params["namespaceArg"])
p.CreateObjForPlugin(gvk, yamlData, n, r, p.Params["namespaceArg"])
// log.Printf("%v %v %v %v %v %v", gvk.Group, gvk.Version, gvk.Kind, n, r, p.Params["namespaceArg"])
objectJSON, err := json.Marshal(manifestWork)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return []string{}
}
// log.Printf("objectJSON: \n%v", string(objectJSON))
p.CreateObjForPlugin(gvk, yamlData, n, r, p.Params["namespaceArg"], objectJSON)
} else {
fmt.Printf("%v", string(yamlData))
}
Expand Down
41 changes: 38 additions & 3 deletions test/alias-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,41 @@ else
fi
((test_number++))


echo
echo "---------------------------------------------"
echo "--- kustomize with KubeStellar bindingpolicy creation (should fail unless you have WDS1 for KubeStellar on context cluster) ---"
echo "k apply -k ../examples/kustomize -l app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-bp-name=newbp --l-bp-wds=wds1"
if ! k apply -k ../examples/kustomize -l app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-bp-name=newbp --l-bp-wds=wds1;then
print_error "test $test_number: ERROR"
else
print_success "test $test_number: SUCCESS"
fi
((test_number++))

echo
echo "---------------------------------------------"
echo "--- kustomize with OCM manifestwork output ---"
echo "k apply -f examples/kubectl/pass --label=app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-mw-name=new"
if ! k apply -f ../examples/kubectl/pass --label=app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-mw-name=new;then
print_error "test $test_number: ERROR"
else
print_success "test $test_number: SUCCESS"
fi
((test_number++))

echo
echo "---------------------------------------------"
echo "--- kustomize with OCM manifestwork creation (should fail unless you have OCM installed on context cluster) ---"
echo "k apply -f examples/kubectl/pass --label=app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-mw-name=new --l-mw-create"
if ! k apply -f ../examples/kubectl/pass --label=app.kubernetes.io/part-of=sample --context=kind-kind --namespace=default --overwrite --l-mw-name=new --l-mw-create;then
print_error "test $test_number: ERROR"
else
print_success "test $test_number: SUCCESS"
fi
((test_number++))


echo
echo "---------------------------------------------"
echo "--- kustomize with debug output ---"
Expand All @@ -188,9 +223,9 @@ fi

echo
echo "---------------------------------------------"
echo "--- kubectl log - works! ---"
echo "k logs deployment.apps/coredns -n kube-system"
if ! k logs deployment.apps/coredns -n kube-system;then
echo "--- kubectl log ---"
echo "k logs deployment.apps/my-app-deployment -n default --context=kind-kind"
if ! k logs deployment.apps/my-app-deployment -n default --context=kind-kind;then
print_error "test $test_number: ERROR"
else
print_success "test $test_number: SUCCESS"
Expand Down

0 comments on commit fe33ea7

Please sign in to comment.