github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/webhooks/multicluster_validation.go (about)

     1  // Copyright (c) 2021, 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  	"fmt"
     9  
    10  	clusters "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1"
    11  	"github.com/verrazzano/verrazzano/application-operator/constants"
    12  	clusterutil "github.com/verrazzano/verrazzano/application-operator/controllers/clusters"
    13  	core "k8s.io/api/core/v1"
    14  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    15  	"k8s.io/apimachinery/pkg/runtime/schema"
    16  	"sigs.k8s.io/controller-runtime/pkg/client"
    17  	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
    18  )
    19  
    20  func validateMultiClusterResource(c client.Client, r clusterutil.MultiClusterResource) error {
    21  	p := r.GetPlacement()
    22  	if len(p.Clusters) == 0 {
    23  		return fmt.Errorf("One or more target clusters must be provided")
    24  	}
    25  	if !isLocalClusterManagedCluster(c) {
    26  		if err := validateTargetClustersExist(c, p); err != nil {
    27  			return err
    28  		}
    29  	}
    30  	return nil
    31  }
    32  
    33  // isLocalClusterManagedCluster determines if the local cluster is a registered managed cluster.
    34  func isLocalClusterManagedCluster(c client.Client) bool {
    35  	s := core.Secret{}
    36  	k := client.ObjectKey{Name: constants.MCRegistrationSecret, Namespace: constants.VerrazzanoSystemNamespace}
    37  	err := c.Get(context.TODO(), k, &s)
    38  	return err == nil
    39  }
    40  
    41  // validateTargetClustersExist determines if all of the target clusters of the project have
    42  // corresponding managed cluster resources.  The results are only valid when this
    43  // is executed against an admin cluster.
    44  func validateTargetClustersExist(c client.Client, p clusters.Placement) error {
    45  	for _, cluster := range p.Clusters {
    46  		targetClusterName := cluster.Name
    47  		// If the target cluster name is local then assume it is valid.
    48  		if targetClusterName != constants.DefaultClusterName {
    49  			key := client.ObjectKey{Name: targetClusterName, Namespace: constants.VerrazzanoMultiClusterNamespace}
    50  			// Need to use unstructured here to avoid a dependency on the platform operator
    51  			vmc := unstructured.Unstructured{}
    52  			vmc.SetGroupVersionKind(schema.GroupVersionKind{
    53  				Group:   "clusters.verrazzano.io",
    54  				Version: "v1alpha1",
    55  				Kind:    "VerrazzanoManagedCluster",
    56  			})
    57  			vmc.SetNamespace(constants.VerrazzanoMultiClusterNamespace)
    58  			vmc.SetName(targetClusterName)
    59  			err := c.Get(context.TODO(), key, &vmc)
    60  			if err != nil {
    61  				return fmt.Errorf("target managed cluster %s is not registered: %v", cluster.Name, err)
    62  			}
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  // translateErrorToResponse translates an error to an admission.Response
    69  func translateErrorToResponse(err error) admission.Response {
    70  	if err == nil {
    71  		return admission.Allowed("")
    72  	}
    73  	return admission.Denied(err.Error())
    74  }