github.com/verrazzano/verrazzano@v1.7.1/cluster-operator/controllers/vmc/push_manifest_objects.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 vmc
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	clusterapi "github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    10  	internalcapi "github.com/verrazzano/verrazzano/cluster-operator/internal/capi"
    11  	constants2 "github.com/verrazzano/verrazzano/pkg/constants"
    12  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    13  	"github.com/verrazzano/verrazzano/pkg/rancherutil"
    14  	"github.com/verrazzano/verrazzano/platform-operator/constants"
    15  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/common"
    16  	corev1 "k8s.io/api/core/v1"
    17  	"k8s.io/apimachinery/pkg/api/errors"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    20  	"k8s.io/apimachinery/pkg/types"
    21  	ctrl "sigs.k8s.io/controller-runtime"
    22  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    23  )
    24  
    25  // pushManifestObjects applies the Verrazzano manifest objects to the managed cluster.
    26  // To access the managed cluster, we are taking advantage of the Rancher proxy or CAPI based access.
    27  func (r *VerrazzanoManagedClusterReconciler) pushManifestObjects(ctx context.Context, rancherEnabled bool, vmc *clusterapi.VerrazzanoManagedCluster) (bool, error) {
    28  	pushed := false
    29  	var err error
    30  	if vmc.Status.ClusterRef != nil {
    31  		pushed, err = r.pushViaCAPIClient(ctx, vmc, rancherEnabled)
    32  		if err != nil {
    33  			return pushed, err
    34  		}
    35  	}
    36  	if !pushed && rancherEnabled {
    37  		pushed, err = r.pushViaRancherProxy(vmc)
    38  		if err != nil {
    39  			return pushed, err
    40  		}
    41  	}
    42  	return pushed, nil
    43  }
    44  
    45  func (r *VerrazzanoManagedClusterReconciler) pushViaRancherProxy(vmc *clusterapi.VerrazzanoManagedCluster) (bool, error) {
    46  	clusterID := vmc.Status.RancherRegistration.ClusterID
    47  	if len(clusterID) == 0 {
    48  		r.log.Progressf("Waiting to push manifest objects, Rancher ClusterID not found in the VMC %s/%s status", vmc.GetNamespace(), vmc.GetName())
    49  		return false, nil
    50  	}
    51  	rc, err := rancherutil.NewVerrazzanoClusterRancherConfig(r.Client, r.RancherIngressHost, r.log)
    52  	if err != nil || rc == nil {
    53  		return false, err
    54  	}
    55  
    56  	// If the managed cluster is not active, we should not attempt to push resources
    57  	isActive, err := isManagedClusterActiveInRancher(rc, clusterID, r.log)
    58  	if err != nil {
    59  		return false, err
    60  	}
    61  
    62  	vsNamespaceCreated, _ := isNamespaceCreated(vmc, r, clusterID, constants.VerrazzanoSystemNamespace)
    63  	if isActive && vsNamespaceCreated {
    64  
    65  		// Create or Update the agent and registration secrets
    66  		agentSecret := corev1.Secret{}
    67  		agentSecret.Namespace = constants.VerrazzanoSystemNamespace
    68  		agentSecret.Name = constants.MCAgentSecret
    69  		regSecret := corev1.Secret{}
    70  		regSecret.Namespace = constants.VerrazzanoSystemNamespace
    71  		regSecret.Name = constants.MCRegistrationSecret
    72  		agentOperation, err := createOrUpdateSecretRancherProxy(&agentSecret, rc, clusterID, func() error {
    73  			existingAgentSec, err := r.getSecret(vmc.Namespace, GetAgentSecretName(vmc.Name), true)
    74  			if err != nil {
    75  				return err
    76  			}
    77  			agentSecret.Data = existingAgentSec.Data
    78  			return nil
    79  		}, r.log)
    80  		if err != nil {
    81  			return false, err
    82  		}
    83  		regOperation, err := createOrUpdateSecretRancherProxy(&regSecret, rc, clusterID, func() error {
    84  			existingRegSecret, err := r.getSecret(vmc.Namespace, GetRegistrationSecretName(vmc.Name), true)
    85  			if err != nil {
    86  				return err
    87  			}
    88  			regSecret.Data = existingRegSecret.Data
    89  			return nil
    90  		}, r.log)
    91  		if err != nil {
    92  			return false, err
    93  		}
    94  		agentModified := agentOperation != controllerutil.OperationResultNone
    95  		regModified := regOperation != controllerutil.OperationResultNone
    96  		return agentModified || regModified, nil
    97  	}
    98  	return false, nil
    99  }
   100  
   101  func (r *VerrazzanoManagedClusterReconciler) pushViaCAPIClient(ctx context.Context, vmc *clusterapi.VerrazzanoManagedCluster, rancherEnabled bool) (bool, error) {
   102  	r.log.Debugf("Pushing via CAPI client, status: %s", vmc.Status.RancherRegistration.Status)
   103  	if vmc.Status.RancherRegistration.Status != clusterapi.RegistrationApplied {
   104  		cluster := &unstructured.Unstructured{}
   105  		cluster.SetGroupVersionKind(internalcapi.GVKCAPICluster)
   106  		err := r.Get(ctx, types.NamespacedName{Namespace: vmc.Status.ClusterRef.Namespace, Name: vmc.Status.ClusterRef.Name}, cluster)
   107  		if err != nil && !errors.IsNotFound(err) {
   108  			return false, err
   109  		}
   110  		manifest, err := r.getClusterManifest(cluster)
   111  		if err != nil {
   112  			return false, err
   113  		}
   114  		// register the cluster if Verrazzano installed on workload cluster
   115  		workloadClient, err := r.getWorkloadClusterClient(cluster)
   116  		if err != nil {
   117  			r.log.Errorf("Error getting workload cluster %s client: %v", cluster.GetName(), err)
   118  			return false, err
   119  		}
   120  
   121  		// apply the manifest to workload cluster
   122  		yamlApplier := k8sutil.NewYAMLApplier(workloadClient, "")
   123  		err = yamlApplier.ApplyS(string(manifest))
   124  		if err != nil {
   125  			r.log.Errorf("Failed applying cluster manifest to workload cluster %s: %v", cluster.GetName(), err)
   126  			return false, err
   127  		}
   128  		r.log.Infof("Registration manifest applied to cluster %s", cluster.GetName())
   129  
   130  		// update the registration status if Rancher is enabled since repeated application of the manifest will
   131  		// trigger connection issues
   132  		if rancherEnabled && vmc.Status.RancherRegistration.Status == clusterapi.RegistrationCompleted {
   133  			existingVMC := &clusterapi.VerrazzanoManagedCluster{}
   134  			err = r.Get(ctx, types.NamespacedName{Namespace: vmc.Namespace, Name: vmc.Name}, existingVMC)
   135  			if err != nil {
   136  				return false, err
   137  			}
   138  			existingVMC.Status.RancherRegistration.Status = clusterapi.RegistrationApplied
   139  			err = r.Status().Update(ctx, existingVMC)
   140  			if err != nil {
   141  				r.log.Errorf("Error updating VMC status for cluster %s: %v", cluster.GetName(), err)
   142  				return false, err
   143  			}
   144  			r.log.Debugf("Registration status updated to Applied")
   145  			vmc = existingVMC
   146  
   147  			// get and label the cattle-system namespace
   148  			ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: common.CattleSystem}}
   149  			if _, err := ctrl.CreateOrUpdate(ctx, workloadClient, ns, func() error {
   150  				if ns.Labels == nil {
   151  					ns.Labels = make(map[string]string)
   152  				}
   153  				ns.Labels[constants2.LabelVerrazzanoNamespace] = common.CattleSystem
   154  				return nil
   155  			}); err != nil {
   156  				return false, err
   157  			}
   158  		}
   159  		return true, nil
   160  	}
   161  	return false, nil
   162  }
   163  
   164  // getClusterManifest retrieves the registration manifest for the workload cluster
   165  func (r *VerrazzanoManagedClusterReconciler) getClusterManifest(cluster *unstructured.Unstructured) ([]byte, error) {
   166  	// retrieve the manifest for the workload cluster
   167  	resourceName := getClusterResourceName(cluster, r.Client)
   168  	manifestSecret := &corev1.Secret{}
   169  	err := r.Get(context.TODO(), types.NamespacedName{
   170  		Name:      fmt.Sprintf("verrazzano-cluster-%s-manifest", resourceName),
   171  		Namespace: constants.VerrazzanoMultiClusterNamespace},
   172  		manifestSecret)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	manifest, ok := manifestSecret.Data["yaml"]
   177  	if !ok {
   178  		return nil, fmt.Errorf("Error retrieving cluster manifest for %s", cluster.GetName())
   179  	}
   180  	return manifest, nil
   181  }