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  }