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  }