github.com/verrazzano/verrazzano@v1.7.0/platform-operator/controllers/integration/opensearch/reconciler.go (about) 1 // Copyright (c) 2022, 2023, 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 opensearch 5 6 import ( 7 "context" 8 "fmt" 9 "time" 10 11 "github.com/verrazzano/verrazzano-modules/pkg/controller/result" 12 "k8s.io/apimachinery/pkg/types" 13 14 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 15 "github.com/verrazzano/verrazzano/pkg/vzcr" 16 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/common" 17 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/opensearch" 18 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/opensearchdashboards" 19 componentspi "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/spi" 20 21 "github.com/verrazzano/verrazzano-modules/pkg/controller/spi/controllerspi" 22 "go.uber.org/zap" 23 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 24 25 vzv1alpha1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1" 26 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/transform" 27 ) 28 29 // Reconcile reconciles the OpenSearch integration configmap. 30 // The configmap existence is just used as a mechanism to trigger reconcile, there 31 // is nothing in the configmap that is needed to do reconcile. 32 func (r Reconciler) Reconcile(controllerCtx controllerspi.ReconcileContext, u *unstructured.Unstructured) result.Result { 33 actualCR, err := r.GetVerrazzanoCR() 34 if err != nil { 35 vzlog.DefaultLogger().ErrorfThrottled("Failed to get Verrazzano CR for OpenSearch integration operator: %v", err) 36 return result.NewResultRequeueDelay(30, 40, time.Second) 37 } 38 39 // Get the resource logger needed to log message using 'progress' and 'once' methods 40 log, err := vzlog.EnsureResourceLogger(&vzlog.ResourceConfig{ 41 Name: actualCR.Name, 42 Namespace: actualCR.Namespace, 43 ID: string(actualCR.UID), 44 Generation: actualCR.Generation, 45 ControllerName: "opensearch-integration", 46 }) 47 if err != nil { 48 zap.S().Errorf("Failed to create logger for opensearch integration controller: %v", err) 49 } 50 r.log = log 51 52 log.Oncef("Starting OpenSearch integration controller for index patterns and ISM policies") 53 54 // Get effective CR. 55 effectiveCR, err := transform.GetEffectiveCR(actualCR) 56 if err != nil { 57 return result.NewResultShortRequeueDelayWithError(err) 58 } 59 componentCtx, err := componentspi.NewContext(log, r.Client, actualCR, nil, false) 60 if err != nil { 61 return result.NewResultShortRequeueDelayWithError(err) 62 } 63 isLegacyOS, err := common.IsLegacyOS(componentCtx) 64 if err != nil { 65 return result.NewResultShortRequeueDelayWithError(err) 66 } 67 68 // Handle only if it's opensearch-operator managed OS 69 if isLegacyOS { 70 return result.NewResult() 71 } 72 73 // Add default index patterns and ISM policies 74 if !areComponentsEnabled(effectiveCR) || !isComponentReady(actualCR, opensearch.ComponentName) || 75 !isComponentReady(actualCR, opensearchdashboards.ComponentName) { 76 // both components must be enabled and ready 77 return result.NewResultRequeueDelay(1, 2, time.Minute) 78 } 79 err = r.CreateIndexPatterns(controllerCtx, effectiveCR) 80 if err != nil { 81 return result.NewResultShortRequeueDelayWithError(err) 82 } 83 if common.IsSingleMasterNodeCluster(componentCtx) { 84 err = r.AddTemplateAutoExpand(controllerCtx, effectiveCR) 85 if err != nil { 86 return result.NewResultShortRequeueDelayWithError(err) 87 } 88 } 89 if !effectiveCR.Spec.Components.Elasticsearch.DisableDefaultPolicy { 90 err = r.CreateDefaultISMPolicies(controllerCtx, effectiveCR) 91 if err != nil { 92 return result.NewResultShortRequeueDelayWithError(err) 93 } 94 } else { 95 err = r.DeleteDefaultISMPolicies(controllerCtx, effectiveCR) 96 if err != nil { 97 return result.NewResultShortRequeueDelayWithError(err) 98 } 99 } 100 101 err = r.ConfigureISMPolicies(controllerCtx, effectiveCR) 102 if err != nil { 103 return result.NewResultShortRequeueDelayWithError(err) 104 } 105 106 return result.NewResultRequeueDelay(5, 6, time.Minute) 107 } 108 109 // areComponentsEnabled returns true if OpenSearch and OpenSearch Dashboard are both enabled 110 func areComponentsEnabled(effectiveCR *vzv1alpha1.Verrazzano) bool { 111 return vzcr.IsOpenSearchEnabled(effectiveCR) && vzcr.IsOpenSearchDashboardsEnabled(effectiveCR) 112 } 113 114 // isComponentReady returns true if the compoent is ready 115 func isComponentReady(actualCR *vzv1alpha1.Verrazzano, compName string) bool { 116 comp := actualCR.Status.Components[compName] 117 return comp != nil && comp.State == vzv1alpha1.CompStateReady 118 } 119 120 // CreateIndexPatterns creates the required index patterns using osd client 121 func (r Reconciler) CreateIndexPatterns(controllerCtx controllerspi.ReconcileContext, vz *vzv1alpha1.Verrazzano) error { 122 pas, err := opensearch.GetVerrazzanoPassword(r.Client) 123 if err != nil { 124 return err 125 } 126 osDashboardsClient := opensearchdashboards.NewOSDashboardsClient(pas) 127 osdURL, err := opensearch.GetOSDHTTPEndpoint(r.Client) 128 if err != nil { 129 return err 130 } 131 return osDashboardsClient.CreateDefaultIndexPatterns(r.log, osdURL) 132 } 133 134 // CreateDefaultISMPolicies creates default ISM policies in OpenSearch 135 func (r Reconciler) CreateDefaultISMPolicies(controllerCtx controllerspi.ReconcileContext, vz *vzv1alpha1.Verrazzano) error { 136 osClient, err := r.getOSClient() 137 if err != nil { 138 return err 139 } 140 err = osClient.SyncDefaultISMPolicy(r.log, r.Client, vz) 141 return err 142 } 143 144 // DeleteDefaultISMPolicies deletes default ISM polcies from OpenSearch 145 func (r Reconciler) DeleteDefaultISMPolicies(controllerCtx controllerspi.ReconcileContext, vz *vzv1alpha1.Verrazzano) error { 146 osClient, err := r.getOSClient() 147 if err != nil { 148 return err 149 } 150 err = osClient.DeleteDefaultISMPolicy(r.log, r.Client, vz) 151 return err 152 } 153 154 // ConfigureISMPolicies configures ISM policies added by user in Vz cr 155 func (r Reconciler) ConfigureISMPolicies(controllerCtx controllerspi.ReconcileContext, vz *vzv1alpha1.Verrazzano) error { 156 osClient, err := r.getOSClient() 157 if err != nil { 158 return err 159 } 160 err = osClient.ConfigureISM(r.log, r.Client, vz) 161 return err 162 } 163 164 // AddAutoExpandTemplate adds template to add auto expand setting for the indices 165 func (r Reconciler) AddTemplateAutoExpand(controllerCtx controllerspi.ReconcileContext, vz *vzv1alpha1.Verrazzano) error { 166 osClient, err := r.getOSClient() 167 if err != nil { 168 return err 169 } 170 err = osClient.SetAutoExpandIndices(r.log, r.Client, vz) 171 return err 172 } 173 174 // getOSClient gets tbe OS client 175 func (r Reconciler) getOSClient() (*opensearch.OSClient, error) { 176 pas, err := opensearch.GetVerrazzanoPassword(r.Client) 177 if err != nil { 178 return nil, err 179 } 180 osClient := opensearch.NewOSClient(pas) 181 return osClient, nil 182 } 183 184 func (r Reconciler) GetVerrazzanoCR() (*vzv1alpha1.Verrazzano, error) { 185 nsn, err := r.GetVerrazzanoNSN() 186 if err != nil { 187 return nil, err 188 } 189 190 vz := &vzv1alpha1.Verrazzano{} 191 if err := r.Client.Get(context.TODO(), *nsn, vz); err != nil { 192 return nil, err 193 } 194 return vz, nil 195 } 196 197 func (r Reconciler) GetVerrazzanoNSN() (*types.NamespacedName, error) { 198 vzlist := &vzv1alpha1.VerrazzanoList{} 199 if err := r.Client.List(context.TODO(), vzlist); err != nil { 200 return nil, err 201 } 202 if len(vzlist.Items) != 1 { 203 return nil, fmt.Errorf("Failed, found %d Verrazzano CRs in the cluster. There must be exactly 1 Verrazzano CR", len(vzlist.Items)) 204 } 205 vz := vzlist.Items[0] 206 return &types.NamespacedName{Namespace: vz.Namespace, Name: vz.Name}, nil 207 }