github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/navigation/unstructured.go (about) 1 // Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package navigation 5 6 import ( 7 "context" 8 "fmt" 9 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" 10 vzapi "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1" 11 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 12 "go.uber.org/zap" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/apimachinery/pkg/conversion" 15 "k8s.io/apimachinery/pkg/runtime" 16 "k8s.io/apimachinery/pkg/types" 17 "sigs.k8s.io/controller-runtime/pkg/client" 18 ) 19 20 // GetKindOfUnstructured get the Kubernetes kind for an unstructured resource. 21 func GetKindOfUnstructured(u *unstructured.Unstructured) (string, error) { 22 if u == nil { 23 return "", fmt.Errorf("invalid unstructured reference") 24 } 25 kind, found := u.Object["kind"].(string) 26 if !found { 27 return "", fmt.Errorf("unstructured does not contain kind") 28 } 29 return kind, nil 30 } 31 32 // GetAPIVersionOfUnstructured gets the Kubernetes apiVersion of the unstructured resource. 33 func GetAPIVersionOfUnstructured(u *unstructured.Unstructured) (string, error) { 34 if u == nil { 35 return "", fmt.Errorf("invalid unstructured reference") 36 } 37 kind, found := u.Object["apiVersion"].(string) 38 if !found { 39 return "", fmt.Errorf("unstructured does not contain api version") 40 } 41 return kind, nil 42 } 43 44 // GetAPIVersionKindOfUnstructured gets the Kubernetes apiVersion.kind of the unstructured resource. 45 func GetAPIVersionKindOfUnstructured(u *unstructured.Unstructured) (string, error) { 46 if u == nil { 47 return "", fmt.Errorf("invalid unstructured reference") 48 } 49 version, err := GetAPIVersionOfUnstructured(u) 50 if err != nil { 51 return "", err 52 } 53 kind, err := GetKindOfUnstructured(u) 54 if err != nil { 55 return "", err 56 } 57 return fmt.Sprintf("%s.%s", version, kind), nil 58 } 59 60 // FetchUnstructuredChildResourcesByAPIVersionKinds find all of the child resource of specific kinds 61 // having a specific parent (workload) UID. The child kinds are APIVersion and Kind 62 // (e.g. apps/v1.Deployment or v1.Service). The objects of these resource kinds are listed 63 // and the ones having the correct parent UID are collected and accumulated and returned. 64 // This is used to collect a subset children of a particular parent object. 65 // There is a case where the parent (workload) UID is equal to the child kind referenced, native Kubernetes types such as Deployment 66 // ctx - The calling context 67 // namespace - The namespace to search for children objects 68 // parentUID - The parent UID a child must have to be included in the result. 69 // childResKinds - The set of resource kinds a child's resource kind must in to be included in the result. 70 func FetchUnstructuredChildResourcesByAPIVersionKinds(ctx context.Context, cli client.Reader, log vzlog.VerrazzanoLogger, namespace string, parentUID types.UID, childResKinds []v1alpha2.ChildResourceKind) ([]*unstructured.Unstructured, error) { 71 var childResources []*unstructured.Unstructured 72 log.Debugf("Fetch children, parent: %s", parentUID) 73 for _, childResKind := range childResKinds { 74 resources := unstructured.UnstructuredList{} 75 resources.SetAPIVersion(childResKind.APIVersion) 76 resources.SetKind(childResKind.Kind) 77 if childResKind.Selector != nil { 78 options := []client.ListOption{client.InNamespace(namespace), client.MatchingLabels(childResKind.Selector)} 79 if err := cli.List(ctx, &resources, options...); err != nil { 80 log.Errorf("Failed listing children: %v", err) 81 return nil, err 82 } 83 } else { 84 options := []client.ListOption{client.InNamespace(namespace)} 85 if err := cli.List(ctx, &resources, options...); err != nil { 86 log.Errorf("Failed listing children: %v", err) 87 return nil, err 88 } 89 } 90 for i, item := range resources.Items { 91 // The Kubernetes Deployment Case where Workload is the Child 92 if item.GetUID() == parentUID { 93 childResources = append(childResources, &resources.Items[i]) 94 break 95 } 96 for _, owner := range item.GetOwnerReferences() { 97 if owner.UID == parentUID { 98 childResources = append(childResources, &resources.Items[i]) 99 break 100 } 101 } 102 } 103 } 104 return childResources, nil 105 } 106 107 // FetchUnstructuredByReference fetches an unstructured using the namespace and name from a qualified resource relation. 108 func FetchUnstructuredByReference(ctx context.Context, cli client.Reader, log *zap.SugaredLogger, reference vzapi.QualifiedResourceRelation) (*unstructured.Unstructured, error) { 109 var uns unstructured.Unstructured 110 uns.SetAPIVersion(reference.APIVersion) 111 uns.SetKind(reference.Kind) 112 key := client.ObjectKey{Name: reference.Name, Namespace: reference.Namespace} 113 log.Debugw("Fetch related resource", "resource", key) 114 if err := cli.Get(ctx, key, &uns); err != nil { 115 return nil, err 116 } 117 return &uns, nil 118 } 119 120 // ConvertRawExtensionToUnstructured converts a runtime.RawExtension to unstructured.Unstructured. The 121 // CRDs for our wrapping types embed a runtime.RawExtension for the actual workload spec (e.g. WebLogic 122 // Domain, Coherence) 123 func ConvertRawExtensionToUnstructured(rawExtension *runtime.RawExtension) (*unstructured.Unstructured, error) { 124 var obj runtime.Object 125 var scope conversion.Scope 126 if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(rawExtension, &obj, scope); err != nil { 127 return nil, err 128 } 129 130 innerObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) 131 if err != nil { 132 return nil, err 133 } 134 135 return &unstructured.Unstructured{Object: innerObj}, nil 136 }