github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/webhooks/metrics_trait_defaulter.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 webhooks 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 11 oamv1 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" 12 "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1" 13 "github.com/verrazzano/verrazzano/application-operator/controllers/metricstrait" 14 vznav "github.com/verrazzano/verrazzano/application-operator/controllers/navigation" 15 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 16 "go.uber.org/zap" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/types" 19 "sigs.k8s.io/controller-runtime/pkg/client" 20 ) 21 22 // MetricsTraitDefaulter supplies default MetricsTrait 23 type MetricsTraitDefaulter struct { 24 Client client.Client 25 } 26 27 var ( 28 apiVersion = v1alpha1.SchemeGroupVersion.String() 29 defaultMetricsTrait = []byte(fmt.Sprintf(traitTemp, apiVersion, v1alpha1.MetricsTraitKind)) 30 ) 31 32 const traitTemp = `{ 33 "apiVersion": "%s", 34 "kind": "%s" 35 }` 36 37 func (m *MetricsTraitDefaulter) findMetricsTrait(component *oamv1.ApplicationConfigurationComponent) bool { 38 for _, trait := range component.Traits { 39 var rawTrait map[string]interface{} 40 json.Unmarshal(trait.Trait.Raw, &rawTrait) 41 if rawTrait["apiVersion"] == apiVersion && rawTrait["kind"] == v1alpha1.MetricsTraitKind { 42 return true 43 } 44 } 45 return false 46 } 47 48 func (m *MetricsTraitDefaulter) addDefaultTrait(component *oamv1.ApplicationConfigurationComponent) { 49 rawTrait := runtime.RawExtension{Raw: defaultMetricsTrait} 50 componentTrait := oamv1.ComponentTrait{Trait: rawTrait} 51 component.Traits = append(component.Traits, componentTrait) 52 } 53 54 // Default method adds default MetricsTrait to ApplicationConfiguration 55 func (m *MetricsTraitDefaulter) Default(appConfig *oamv1.ApplicationConfiguration, dryRun bool, log *zap.SugaredLogger) error { 56 for i := range appConfig.Spec.Components { 57 appConfigComponent := &appConfig.Spec.Components[i] 58 if m.shouldDefaultTraitBeAdded(appConfig, appConfigComponent, log) { 59 m.addDefaultTrait(appConfigComponent) 60 } 61 } 62 return nil 63 } 64 65 // Cleanup is not used by the metrics trait defaulter 66 func (m *MetricsTraitDefaulter) Cleanup(appConfig *oamv1.ApplicationConfiguration, dryRun bool, log *zap.SugaredLogger) error { 67 return nil 68 } 69 70 // shouldDefaultTraitBeAdded method verifies whether a trait should be applied to the component 71 func (m *MetricsTraitDefaulter) shouldDefaultTraitBeAdded(appConfig *oamv1.ApplicationConfiguration, appConfigComponent *oamv1.ApplicationConfigurationComponent, log *zap.SugaredLogger) bool { 72 found := m.findMetricsTrait(appConfigComponent) 73 if found { 74 return false 75 } 76 77 var component oamv1.Component 78 err := m.Client.Get(context.TODO(), types.NamespacedName{Namespace: appConfig.GetNamespace(), Name: appConfigComponent.ComponentName}, &component) 79 if err != nil { 80 log.Debugf("Unable to get component info for component: %s of application configuration: %s/%s, error: %v, adding default metric trait", appConfigComponent.ComponentName, appConfig.GetNamespace(), appConfig.GetName(), err) 81 return true 82 83 } 84 85 componentUnstructured, err := vznav.ConvertRawExtensionToUnstructured(&component.Spec.Workload) 86 if err != nil || componentUnstructured == nil { 87 log.Debugf("Unable to convert workload spec for component: %s of application configuration: %s/%s, error: %v, adding default metric trait", appConfigComponent.ComponentName, appConfig.GetNamespace(), appConfig.GetName(), err) 88 return true 89 } 90 91 if componentUnstructured.GetNamespace() == "" { 92 componentUnstructured.SetNamespace(component.GetNamespace()) 93 } 94 95 workload, err := vznav.FetchWorkloadResource(context.TODO(), m.Client, vzlog.DefaultLogger(), componentUnstructured) 96 if err != nil || workload == nil { 97 log.Debugf("Unable to get workload resource for component: %s of application configuration: %s/%s, error: %v, adding default metric trait", appConfigComponent.ComponentName, appConfig.GetNamespace(), appConfig.GetName(), err) 98 return true 99 } 100 101 apiVerKind, err := vznav.GetAPIVersionKindOfUnstructured(workload) 102 if err != nil || apiVerKind == "" { 103 log.Debugf("Unable to determine api version and kind for workload of component: %s of application configuration: %s/%s, error: %v, adding default metric trait", appConfigComponent.ComponentName, appConfig.GetNamespace(), appConfig.GetName(), err) 104 return true 105 } 106 107 workloadType := metricstrait.GetSupportedWorkloadType(apiVerKind) 108 if workloadType != "" { 109 log.Infof("Adding default metrics trait for supported component: %s of type %s of application configuration: %s/%s", appConfigComponent.ComponentName, workloadType, appConfig.GetNamespace(), appConfig.GetName()) 110 return true 111 } 112 113 return false 114 }