...

Source file src/github.com/redhat-developer/odo/pkg/service/link.go

Documentation: github.com/redhat-developer/odo/pkg/service

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/devfile/library/v2/pkg/devfile/generator"
     7  	appsv1 "k8s.io/api/apps/v1"
     8  	kerrors "k8s.io/apimachinery/pkg/api/errors"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    11  	"k8s.io/apimachinery/pkg/runtime"
    12  	authv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
    13  	"k8s.io/klog"
    14  	ctrl "sigs.k8s.io/controller-runtime"
    15  
    16  	"github.com/redhat-developer/odo/pkg/kclient"
    17  	odolabels "github.com/redhat-developer/odo/pkg/labels"
    18  
    19  	sboApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
    20  	sboKubernetes "github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes"
    21  	sboPipeline "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
    22  	sboContext "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context"
    23  )
    24  
    25  // pushLinksWithoutOperator creates links (if service binding operator is not installed) between components and services
    26  func pushLinksWithoutOperator(client kclient.ClientInterface, u unstructured.Unstructured, labels map[string]string) error {
    27  
    28  	// check csv support before proceeding
    29  	csvSupport, err := client.IsCSVSupported()
    30  	if err != nil {
    31  		return err
    32  	}
    33  
    34  	var serviceCompMap map[string]string
    35  
    36  	// create the links
    37  	// prevent listing of services unless required
    38  	services, e := client.ListServices("")
    39  	if e != nil {
    40  		return e
    41  	}
    42  
    43  	// get the services and get match them against the component
    44  	serviceCompMap = make(map[string]string)
    45  	for _, service := range services {
    46  		serviceCompMap[service.Name] = odolabels.GetComponentName(service.Labels)
    47  	}
    48  
    49  	// get the string representation of the YAML definition of a CRD
    50  	var serviceBinding sboApi.ServiceBinding
    51  	err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), &serviceBinding)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	if len(serviceBinding.Spec.Services) != 1 {
    57  		klog.V(4).Infof("cannot create the link; serviceBinding.Spec.Services != 1; ServiceBinding: %v", serviceBinding)
    58  		return nil
    59  	}
    60  
    61  	if !csvSupport && !isLinkResource(serviceBinding.Spec.Services[0].Kind) {
    62  		// ignore service binding objects linked to services if csv support is not present on the cluster
    63  		klog.V(4).Infof("cannot create the link; CSV is not supported")
    64  		return nil
    65  	}
    66  
    67  	// set the labels and namespace
    68  	serviceBinding.SetLabels(labels)
    69  	serviceBinding.Namespace = client.GetCurrentNamespace()
    70  	ns := client.GetCurrentNamespace()
    71  	serviceBinding.Spec.Services[0].Namespace = &ns
    72  
    73  	var processingPipeline sboPipeline.Pipeline
    74  	processingPipeline, err = getPipeline(client)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	_, err = processingPipeline.Process(&serviceBinding)
    80  	if err != nil {
    81  		if kerrors.IsForbidden(err) {
    82  			// due to https://github.com/redhat-developer/service-binding-operator/issues/1003
    83  			return fmt.Errorf("please install the service binding operator")
    84  		}
    85  		return err
    86  	}
    87  
    88  	if len(serviceBinding.Status.Secret) == 0 {
    89  		return fmt.Errorf("no secret was provided by service binding's pipleine")
    90  	}
    91  
    92  	// get the generated secret and update it with the labels and owner reference
    93  	sbSecret, err := client.GetSecret(serviceBinding.Status.Secret, client.GetCurrentNamespace())
    94  	if err != nil {
    95  		return err
    96  	}
    97  	sbSecret.Labels = labels
    98  	sbSecret.Labels[LinkLabel] = serviceBinding.Name
    99  	if _, ok := serviceCompMap[serviceBinding.Spec.Services[0].Name]; ok {
   100  		sbSecret.Labels[ServiceLabel] = serviceCompMap[serviceBinding.Spec.Services[0].Name]
   101  	} else {
   102  		sbSecret.Labels[ServiceLabel] = serviceBinding.Spec.Services[0].Name
   103  	}
   104  	sbSecret.Labels[ServiceKind] = serviceBinding.Spec.Services[0].Kind
   105  
   106  	if serviceBinding.Spec.Services[0].Kind != "Service" {
   107  		// the service name is stored as kind-name as `/` is not a valid char for labels of kubernetes secrets
   108  		sbSecret.Labels[ServiceLabel] = fmt.Sprintf("%v-%v", serviceBinding.Spec.Services[0].Kind, serviceBinding.Spec.Services[0].Name)
   109  	}
   110  
   111  	// Obtain the component deployment to set as owner reference; this ensures the secret gets deleted when deployment does
   112  	deployment, err := client.GetOneDeploymentFromSelector(odolabels.GetSelector(odolabels.GetComponentName(labels), odolabels.GetAppName(labels), odolabels.ComponentAnyMode, true))
   113  	if err != nil {
   114  		return err
   115  	}
   116  	ownerReferences := generator.GetOwnerReference(deployment)
   117  	sbSecret.SetOwnerReferences([]metav1.OwnerReference{ownerReferences})
   118  
   119  	_, err = client.UpdateSecret(sbSecret, client.GetCurrentNamespace())
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  // UnbindWithLibrary unbinds the component and service using the ServiceBinding library; it does not delete the secret
   128  func UnbindWithLibrary(kubeClient kclient.ClientInterface, secretToUnbind unstructured.Unstructured, deployment *appsv1.Deployment) error {
   129  	var processingPipeline sboPipeline.Pipeline
   130  	deploymentGVK, err := kubeClient.GetDeploymentAPIVersion()
   131  	if err != nil {
   132  		return fmt.Errorf("failed to get deployment GVK: %w", err)
   133  	}
   134  	// build the ServiceBinding object to for unbinding
   135  	var newServiceBinding sboApi.ServiceBinding
   136  	newServiceBinding.Name = secretToUnbind.GetLabels()[LinkLabel]
   137  	newServiceBinding.Namespace = kubeClient.GetCurrentNamespace()
   138  	newServiceBinding.Spec.Application = sboApi.Application{
   139  		Ref: sboApi.Ref{
   140  			Name:    deployment.Name,
   141  			Group:   deploymentGVK.Group,
   142  			Version: deploymentGVK.Version,
   143  			Kind:    deploymentGVK.Kind,
   144  		},
   145  	}
   146  	newServiceBinding.Status.Secret = secretToUnbind.GetName()
   147  	// set the deletion time stamp to trigger deletion
   148  	timeNow := metav1.Now()
   149  	newServiceBinding.DeletionTimestamp = &timeNow
   150  
   151  	if processingPipeline == nil {
   152  		processingPipeline, err = getPipeline(kubeClient)
   153  		if err != nil {
   154  			return err
   155  		}
   156  	}
   157  	// use the library to perform unbinding;
   158  	// this will remove all the envvars, volume/secret mounts done on the deployment to bind it to the service
   159  	_, err = processingPipeline.Process(&newServiceBinding)
   160  	return err
   161  }
   162  
   163  // getPipeline gets the pipeline to process service binding requests
   164  func getPipeline(client kclient.ClientInterface) (sboPipeline.Pipeline, error) {
   165  	mgr, err := ctrl.NewManager(client.GetClientConfig(), ctrl.Options{
   166  		Scheme: runtime.NewScheme(),
   167  		// disable the health probes to prevent binding to them
   168  		HealthProbeBindAddress: "0",
   169  		// disable the prometheus metrics
   170  		MetricsBindAddress: "0",
   171  	})
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	authClient, err := authv1.NewForConfig(client.GetClientConfig())
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return OdoDefaultBuilder.WithContextProvider(
   182  		sboContext.Provider(
   183  			client.GetDynamicClient(),
   184  			authClient.SubjectAccessReviews(),
   185  			sboKubernetes.ResourceLookup(mgr.GetRESTMapper()),
   186  		),
   187  	).Build(), nil
   188  }
   189  

View as plain text