diff --git a/internal/controller/reconcile-capapplicationversion.go b/internal/controller/reconcile-capapplicationversion.go index 2e4b4fce..51f587ac 100644 --- a/internal/controller/reconcile-capapplicationversion.go +++ b/internal/controller/reconcile-capapplicationversion.go @@ -49,7 +49,10 @@ type DeploymentParameters struct { CAV *v1alpha1.CAPApplicationVersion OwnerRef *metav1.OwnerReference WorkloadDetails v1alpha1.WorkloadDetails - VCAPSecretName string + Env []corev1.EnvVar + EnvFrom []corev1.EnvFromSource + Volumes []corev1.Volume + VolumeMounts []corev1.VolumeMount } func (c *Controller) reconcileCAPApplicationVersion(ctx context.Context, item QueueItem, attempts int) (*ReconcileResult, error) { @@ -260,10 +263,13 @@ func (c *Controller) handleContentDeployJob(ca *v1alpha1.CAPApplication, cav *v1 ownerRef := *metav1.NewControllerRef(cav, v1alpha1.SchemeGroupVersion.WithKind(v1alpha1.CAPApplicationVersionKind)) // Get VCAP secret name - vcapSecretName, err = createVCAPSecret(jobName, cav.Namespace, ownerRef, consumedServiceInfos, c.kubeClient) + err = nil + if !useVolumeMountsForServiceCredentials(cav) { + vcapSecretName, err = createVCAPSecret(jobName, cav.Namespace, ownerRef, consumedServiceInfos, c.kubeClient) + } if err == nil { - contentDeployJob, err = c.kubeClient.BatchV1().Jobs(cav.Namespace).Create(context.TODO(), newContentDeploymentJob(cav, workload, ownerRef, vcapSecretName), metav1.CreateOptions{}) + contentDeployJob, err = c.kubeClient.BatchV1().Jobs(cav.Namespace).Create(context.TODO(), newContentDeploymentJob(ca, cav, workload, ownerRef, vcapSecretName), metav1.CreateOptions{}) if err == nil { util.LogInfo("Content job created successfully", string(Processing), cav, contentDeployJob, "version", cav.Spec.Version) } @@ -274,7 +280,7 @@ func (c *Controller) handleContentDeployJob(ca *v1alpha1.CAPApplication, cav *v1 } // newContentDeploymentJob creates a Content Deployment Job for the CAV resource. It also sets the appropriate OwnerReferences. -func newContentDeploymentJob(cav *v1alpha1.CAPApplicationVersion, workload *v1alpha1.WorkloadDetails, ownerRef metav1.OwnerReference, vcapSecretName string) *batchv1.Job { +func newContentDeploymentJob(ca *v1alpha1.CAPApplication, cav *v1alpha1.CAPApplicationVersion, workload *v1alpha1.WorkloadDetails, ownerRef metav1.OwnerReference, vcapSecretName string) *batchv1.Job { labels := copyMaps(workload.Labels, map[string]string{ LabelDisableKarydia: "true", }) @@ -287,6 +293,23 @@ func newContentDeploymentJob(cav *v1alpha1.CAPApplicationVersion, workload *v1al util.LogInfo("Creating content job", string(Processing), cav, nil, "contentJobName", contentJobName, "version", cav.Spec.Version) + var envFrom []corev1.EnvFromSource + var serviceSecretVolumeMounts []corev1.VolumeMount + var serviceSecretVolumes []corev1.Volume + + env := workload.JobDefinition.Env + + if useVolumeMountsForServiceCredentials(cav) { + // Get ServiceInfos for consumed BTP services + consumedServiceInfos := getConsumedServiceInfos(getConsumedServiceMap(workload.ConsumedBTPServices), ca.Spec.BTP.Services) + + env = updateServiceBindingRootEnv(env) + serviceSecretVolumeMounts = getServiceCredentialVolumeMounts(consumedServiceInfos) + serviceSecretVolumes = getServiceCredentialVolumes(consumedServiceInfos) + } else { + envFrom = getEnvFrom(vcapSecretName) + } + return &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: contentJobName, @@ -314,19 +337,19 @@ func newContentDeploymentJob(cav *v1alpha1.CAPApplicationVersion, workload *v1al Args: workload.JobDefinition.Args, Env: append([]corev1.EnvVar{ {Name: EnvCAPOpAppVersion, Value: cav.Spec.Version}, - }, workload.JobDefinition.Env...), - EnvFrom: getEnvFrom(vcapSecretName), - VolumeMounts: workload.JobDefinition.VolumeMounts, + }, env...), + EnvFrom: envFrom, + VolumeMounts: append(workload.JobDefinition.VolumeMounts, serviceSecretVolumeMounts...), Resources: workload.JobDefinition.Resources, SecurityContext: workload.JobDefinition.SecurityContext, }, }, InitContainers: *updateInitContainers(workload.JobDefinition.InitContainers, []corev1.EnvVar{ {Name: EnvCAPOpAppVersion, Value: cav.Spec.Version}, - }, vcapSecretName), + }, serviceSecretVolumeMounts, envFrom), SecurityContext: workload.JobDefinition.PodSecurityContext, ServiceAccountName: workload.JobDefinition.ServiceAccountName, - Volumes: workload.JobDefinition.Volumes, + Volumes: append(workload.JobDefinition.Volumes, serviceSecretVolumes...), ImagePullSecrets: convertToLocalObjectReferences(cav.Spec.RegistrySecrets), RestartPolicy: getRestartPolicy(workload.JobDefinition.RestartPolicy, true), NodeSelector: workload.JobDefinition.NodeSelector, @@ -675,7 +698,10 @@ func (c *Controller) updateDeployment(ca *v1alpha1.CAPApplication, cav *v1alpha1 ownerRef := *metav1.NewControllerRef(cav, v1alpha1.SchemeGroupVersion.WithKind(v1alpha1.CAPApplicationVersionKind)) // Get VCAP secret name - vcapSecretName, err = createVCAPSecret(deploymentName, cav.Namespace, ownerRef, consumedServiceInfos, c.kubeClient) + err = nil + if !useVolumeMountsForServiceCredentials(cav) { + vcapSecretName, err = createVCAPSecret(deploymentName, cav.Namespace, ownerRef, consumedServiceInfos, c.kubeClient) + } if err == nil { workloadDeployment, err = c.kubeClient.AppsV1().Deployments(cav.Namespace).Create(context.TODO(), newDeployment(ca, cav, workload, ownerRef, vcapSecretName), metav1.CreateOptions{}) @@ -695,7 +721,18 @@ func newDeployment(ca *v1alpha1.CAPApplication, cav *v1alpha1.CAPApplicationVers CAV: cav, OwnerRef: &ownerRef, WorkloadDetails: *workload, - VCAPSecretName: vcapSecretName, + Env: workload.DeploymentDefinition.Env, + } + + if useVolumeMountsForServiceCredentials(cav) { + // Get ServiceInfos for consumed BTP services + consumedServiceInfos := getConsumedServiceInfos(getConsumedServiceMap(workload.ConsumedBTPServices), ca.Spec.BTP.Services) + + params.Env = updateServiceBindingRootEnv(params.Env) + params.VolumeMounts = getServiceCredentialVolumeMounts(consumedServiceInfos) + params.Volumes = getServiceCredentialVolumes(consumedServiceInfos) + } else { + params.EnvFrom = getEnvFrom(vcapSecretName) } return createDeployment(params) @@ -732,10 +769,10 @@ func createDeployment(params *DeploymentParameters) *appsv1.Deployment { ImagePullSecrets: convertToLocalObjectReferences(params.CAV.Spec.RegistrySecrets), InitContainers: *updateInitContainers(params.WorkloadDetails.DeploymentDefinition.InitContainers, []corev1.EnvVar{ {Name: EnvCAPOpAppVersion, Value: params.CAV.Spec.Version}, - }, params.VCAPSecretName), + }, params.VolumeMounts, params.EnvFrom), Containers: getContainer(params), ServiceAccountName: params.WorkloadDetails.DeploymentDefinition.ServiceAccountName, - Volumes: params.WorkloadDetails.DeploymentDefinition.Volumes, + Volumes: append(params.WorkloadDetails.DeploymentDefinition.Volumes, params.Volumes...), SecurityContext: params.WorkloadDetails.DeploymentDefinition.PodSecurityContext, NodeSelector: params.WorkloadDetails.DeploymentDefinition.NodeSelector, NodeName: params.WorkloadDetails.DeploymentDefinition.NodeName, @@ -758,8 +795,8 @@ func getContainer(params *DeploymentParameters) []corev1.Container { Command: params.WorkloadDetails.DeploymentDefinition.Command, Args: params.WorkloadDetails.DeploymentDefinition.Args, Env: getEnv(params), - EnvFrom: getEnvFrom(params.VCAPSecretName), - VolumeMounts: params.WorkloadDetails.DeploymentDefinition.VolumeMounts, + EnvFrom: params.EnvFrom, + VolumeMounts: append(params.WorkloadDetails.DeploymentDefinition.VolumeMounts, params.VolumeMounts...), LivenessProbe: params.WorkloadDetails.DeploymentDefinition.LivenessProbe, ReadinessProbe: params.WorkloadDetails.DeploymentDefinition.ReadinessProbe, Resources: params.WorkloadDetails.DeploymentDefinition.Resources, @@ -772,7 +809,7 @@ func getEnv(params *DeploymentParameters) []corev1.EnvVar { env := []corev1.EnvVar{ {Name: EnvCAPOpAppVersion, Value: params.CAV.Spec.Version}, } - env = append(env, params.WorkloadDetails.DeploymentDefinition.Env...) + env = append(env, params.Env...) if params.WorkloadDetails.DeploymentDefinition.Type == v1alpha1.DeploymentRouter { // Add destinations env for `Router` diff --git a/internal/controller/reconcile-capapplicationversion_test.go b/internal/controller/reconcile-capapplicationversion_test.go index eb05a8bc..ae6298ab 100644 --- a/internal/controller/reconcile-capapplicationversion_test.go +++ b/internal/controller/reconcile-capapplicationversion_test.go @@ -847,3 +847,21 @@ func TestCAV_InvalidMonitoringConfig(t *testing.T) { } } + +func TestCAV_UseVolumeMount(t *testing.T) { + reconcileTestItem( + context.TODO(), t, + QueueItem{Key: ResourceCAPApplicationVersion, ResourceKey: NamespacedResourceKey{Namespace: "default", Name: "test-cap-01-cav-v1"}}, + TestData{ + description: "capapplication version with initContainers", + initialResources: []string{ + "testdata/common/capapplication.yaml", + "testdata/common/credential-secrets.yaml", + "testdata/capapplicationversion/cav-use-vol-mount.yaml", + }, + expectedResources: "testdata/capapplicationversion/expected/cav-processing-use-vol-mount.yaml", + expectedRequeue: map[int][]NamespacedResourceKey{ResourceCAPApplicationVersion: {{Namespace: "default", Name: "test-cap-01-cav-v1"}}}, + backlogItems: []string{}, + }, + ) +} diff --git a/internal/controller/reconcile-captenantoperation.go b/internal/controller/reconcile-captenantoperation.go index 930b58dd..be2af4a0 100644 --- a/internal/controller/reconcile-captenantoperation.go +++ b/internal/controller/reconcile-captenantoperation.go @@ -391,11 +391,19 @@ func (c *Controller) initiateJobForCAPTenantOperationStep(ctx context.Context, c return nil, fmt.Errorf("could not find workload %s in %s %s.%s", step.Name, v1alpha1.CAPApplicationVersionKind, relatedResources.CAPApplicationVersion.Namespace, relatedResources.CAPApplicationVersion.Name) } - // create VCAP secret from consumed BTP services consumedServiceInfos := getConsumedServiceInfos(getConsumedServiceMap(workload.ConsumedBTPServices), relatedResources.CAPApplication.Spec.BTP.Services) - vcapSecretName, err := createVCAPSecret(ctop.Name+"-"+strings.ToLower(workload.Name), ctop.Namespace, *metav1.NewControllerRef(ctop, v1alpha1.SchemeGroupVersion.WithKind(v1alpha1.CAPTenantOperationKind)), consumedServiceInfos, c.kubeClient) - if err != nil { - return nil, err + + // check volume mount annotation + useVolumeMountsForServiceCredentials := useVolumeMountsForServiceCredentials(relatedResources.CAPApplicationVersion) + + // create VCAP secret from consumed BTP services + var vcapSecretName string + err = nil + if !useVolumeMountsForServiceCredentials { + vcapSecretName, err = createVCAPSecret(ctop.Name+"-"+strings.ToLower(workload.Name), ctop.Namespace, *metav1.NewControllerRef(ctop, v1alpha1.SchemeGroupVersion.WithKind(v1alpha1.CAPTenantOperationKind)), consumedServiceInfos, c.kubeClient) + if err != nil { + return nil, err + } } annotations := copyMaps(workload.Annotations, map[string]string{ @@ -420,7 +428,6 @@ func (c *Controller) initiateJobForCAPTenantOperationStep(ctx context.Context, c namePrefix: relatedResources.CAPTenant.Name + "-" + workload.Name + "-", labels: labels, annotations: annotations, - vcapSecretName: vcapSecretName, imagePullSecrets: convertToLocalObjectReferences(relatedResources.CAPApplicationVersion.Spec.RegistrySecrets), version: relatedResources.CAPApplicationVersion.Spec.Version, appName: relatedResources.CAPApplication.Spec.BTPAppName, @@ -430,6 +437,20 @@ func (c *Controller) initiateJobForCAPTenantOperationStep(ctx context.Context, c tenantType: relatedResources.CAPTenant.Labels[LabelTenantType], } + if workload.DeploymentDefinition == nil { + params.Env = workload.JobDefinition.Env + } else { + params.Env = workload.DeploymentDefinition.Env + } + + if useVolumeMountsForServiceCredentials { + params.Env = updateServiceBindingRootEnv(params.Env) + params.volumeMounts = getServiceCredentialVolumeMounts(consumedServiceInfos) + params.volumes = getServiceCredentialVolumes(consumedServiceInfos) + } else { + params.EnvFrom = getEnvFrom(vcapSecretName) + } + var job *batchv1.Job if ctop.Spec.Steps[*ctop.Status.CurrentStep-1].Type == v1alpha1.JobTenantOperation { job, err = c.createTenantOperationJob(ctx, ctop, workload, params) @@ -454,7 +475,6 @@ type jobCreateParams struct { namePrefix string labels map[string]string annotations map[string]string - vcapSecretName string imagePullSecrets []corev1.LocalObjectReference version string appName string @@ -462,6 +482,10 @@ type jobCreateParams struct { providerTenantId string providerSubdomain string tenantType string + Env []corev1.EnvVar + EnvFrom []corev1.EnvFromSource + volumes []corev1.Volume + volumeMounts []corev1.VolumeMount } func (c *Controller) createTenantOperationJob(ctx context.Context, ctop *v1alpha1.CAPTenantOperation, workload *v1alpha1.WorkloadDetails, params *jobCreateParams) (*batchv1.Job, error) { @@ -488,8 +512,8 @@ func (c *Controller) createTenantOperationJob(ctx context.Context, ctop *v1alpha RestartPolicy: getRestartPolicy(derivedWorkload.restartPolicy, true), ImagePullSecrets: params.imagePullSecrets, Containers: getContainers(ctop, derivedWorkload, workload, params), - InitContainers: *updateInitContainers(derivedWorkload.initContainers, getCTOPEnv(params, ctop, v1alpha1.JobTenantOperation), params.vcapSecretName), - Volumes: derivedWorkload.volumes, + InitContainers: *updateInitContainers(derivedWorkload.initContainers, getCTOPEnv(params, ctop, v1alpha1.JobTenantOperation), params.volumeMounts, params.EnvFrom), + Volumes: append(derivedWorkload.volumes, params.volumes...), ServiceAccountName: derivedWorkload.serviceAccountName, SecurityContext: derivedWorkload.podSecurityContext, NodeSelector: derivedWorkload.nodeSelector, @@ -512,9 +536,9 @@ func getContainers(ctop *v1alpha1.CAPTenantOperation, derivedWorkload tentantOpe Name: workload.Name, Image: derivedWorkload.image, ImagePullPolicy: derivedWorkload.imagePullPolicy, - Env: append(getCTOPEnv(params, ctop, v1alpha1.JobTenantOperation), derivedWorkload.env...), - EnvFrom: getEnvFrom(params.vcapSecretName), - VolumeMounts: derivedWorkload.volumeMounts, + Env: append(getCTOPEnv(params, ctop, v1alpha1.JobTenantOperation), params.Env...), + EnvFrom: params.EnvFrom, + VolumeMounts: append(derivedWorkload.volumeMounts, params.volumeMounts...), Resources: derivedWorkload.resources, SecurityContext: derivedWorkload.securityContext, } @@ -607,7 +631,7 @@ func (c *Controller) createCustomTenantOperationJob(ctx context.Context, ctop *v Spec: corev1.PodSpec{ RestartPolicy: getRestartPolicy(workload.JobDefinition.RestartPolicy, true), SecurityContext: workload.JobDefinition.PodSecurityContext, - Volumes: workload.JobDefinition.Volumes, + Volumes: append(workload.JobDefinition.Volumes, params.volumes...), ServiceAccountName: workload.JobDefinition.ServiceAccountName, NodeSelector: workload.JobDefinition.NodeSelector, NodeName: workload.JobDefinition.NodeName, @@ -621,16 +645,16 @@ func (c *Controller) createCustomTenantOperationJob(ctx context.Context, ctop *v Name: workload.Name, Image: workload.JobDefinition.Image, ImagePullPolicy: workload.JobDefinition.ImagePullPolicy, - Env: append(getCTOPEnv(params, ctop, v1alpha1.JobCustomTenantOperation), workload.JobDefinition.Env...), - EnvFrom: getEnvFrom(params.vcapSecretName), - VolumeMounts: workload.JobDefinition.VolumeMounts, + Env: append(getCTOPEnv(params, ctop, v1alpha1.JobCustomTenantOperation), params.Env...), + EnvFrom: params.EnvFrom, + VolumeMounts: append(workload.JobDefinition.VolumeMounts, params.volumeMounts...), Command: workload.JobDefinition.Command, Args: workload.JobDefinition.Args, Resources: workload.JobDefinition.Resources, SecurityContext: workload.JobDefinition.SecurityContext, }, }, - InitContainers: *updateInitContainers(workload.JobDefinition.InitContainers, getCTOPEnv(params, ctop, v1alpha1.JobCustomTenantOperation), params.vcapSecretName), + InitContainers: *updateInitContainers(workload.JobDefinition.InitContainers, getCTOPEnv(params, ctop, v1alpha1.JobCustomTenantOperation), params.volumeMounts, params.EnvFrom), }, }, }, diff --git a/internal/controller/reconcile-captenantoperation_test.go b/internal/controller/reconcile-captenantoperation_test.go index 086cfcff..ece8baa6 100644 --- a/internal/controller/reconcile-captenantoperation_test.go +++ b/internal/controller/reconcile-captenantoperation_test.go @@ -731,3 +731,47 @@ func TestProvisioningWithInitContainersCustom(t *testing.T) { }, ) } + +func TestProvisioningUsingVolMountForServices(t *testing.T) { + _ = reconcileTestItem( + context.TODO(), t, + QueueItem{Key: ResourceCAPTenantOperation, ResourceKey: NamespacedResourceKey{Namespace: "default", Name: "test-cap-01-provider-abcd"}}, + TestData{ + backlogItems: []string{}, + description: "Provisioning - Using service volume mount for TenantOperation", + initialResources: []string{ + "testdata/common/capapplication.yaml", + "testdata/common/captenant-provider-ready.yaml", + "testdata/common/capapplicationversion-v1-use-vol-mount.yaml", + "testdata/common/credential-secrets.yaml", + "testdata/captenantoperation/ctop-use-vol-mount.initial.yaml", + }, + expectedResources: "testdata/captenantoperation/ctop-use-vol-mount.expected.yaml", + expectedRequeue: map[int][]NamespacedResourceKey{ + ResourceCAPTenantOperation: {{Namespace: "default", Name: "test-cap-01-provider-abcd"}}, + }, + }, + ) +} + +func TestProvisioningUsingVolMountForServicesCustom(t *testing.T) { + _ = reconcileTestItem( + context.TODO(), t, + QueueItem{Key: ResourceCAPTenantOperation, ResourceKey: NamespacedResourceKey{Namespace: "default", Name: "test-cap-01-provider-abcd"}}, + TestData{ + backlogItems: []string{}, + description: "Provisioning - Using service volume mount for CustomTenantOperation", + initialResources: []string{ + "testdata/common/capapplication.yaml", + "testdata/common/captenant-provider-ready.yaml", + "testdata/common/capapplicationversion-v1-use-vol-mount-custom.yaml", + "testdata/common/credential-secrets.yaml", + "testdata/captenantoperation/ctop-use-vol-mount-custom.initial.yaml", + }, + expectedResources: "testdata/captenantoperation/ctop-use-vol-mount-custom.expected.yaml", + expectedRequeue: map[int][]NamespacedResourceKey{ + ResourceCAPTenantOperation: {{Namespace: "default", Name: "test-cap-01-provider-abcd"}}, + }, + }, + ) +} diff --git a/internal/controller/reconcile.go b/internal/controller/reconcile.go index 12a30510..422c0679 100644 --- a/internal/controller/reconcile.go +++ b/internal/controller/reconcile.go @@ -9,10 +9,12 @@ import ( "context" "encoding/json" "fmt" + "path" "strings" "github.com/sap/cap-operator/internal/util" "github.com/sap/cap-operator/pkg/apis/sme.sap.com/v1alpha1" + "golang.org/x/exp/slices" "golang.org/x/mod/semver" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -48,6 +50,7 @@ const ( AnnotationSubscriptionContextSecret = "sme.sap.com/subscription-context-secret" AnnotationProviderSubAccountId = "sme.sap.com/provider-sub-account-id" AnnotationEnableCleanupMonitoring = "sme.sap.com/enable-cleanup-monitoring" + AnnotationUseCredentialVolumeMount = "sme.sap.com/use-credential-volume-mount" FinalizerCAPApplication = "sme.sap.com/capapplication" FinalizerCAPApplicationVersion = "sme.sap.com/capapplicationversion" FinalizerCAPTenant = "sme.sap.com/captenant" @@ -55,6 +58,8 @@ const ( GardenerDNSClassIdentifier = "dns.gardener.cloud/class" ) +var defaultServiceBindingRootEnv = corev1.EnvVar{Name: "SERVICE_BINDING_ROOT", Value: "/etc/secrets"} + const ( CertificateSuffix = "certificate" GardenerDNSClassValue = "garden" @@ -594,14 +599,18 @@ func copyMaps(originalMap map[string]string, additionalMap map[string]string) ma return newMap } -func updateInitContainers(initContainers []corev1.Container, additionalEnv []corev1.EnvVar, vcapSecretName string) *[]corev1.Container { +func updateInitContainers(initContainers []corev1.Container, additionalEnv []corev1.EnvVar, serviceSecretVolumeMounts []corev1.VolumeMount, EnvFrom []corev1.EnvFromSource) *[]corev1.Container { var updatedInitContainers []corev1.Container if len(initContainers) > 0 { updatedInitContainers = []corev1.Container{} for _, container := range initContainers { updatedContainer := container.DeepCopy() updatedContainer.Env = append(updatedContainer.Env, additionalEnv...) - updatedContainer.EnvFrom = getEnvFrom(vcapSecretName) + updatedContainer.EnvFrom = EnvFrom + if len(serviceSecretVolumeMounts) > 0 { + updatedContainer.VolumeMounts = append(updatedContainer.VolumeMounts, serviceSecretVolumeMounts...) + updatedContainer.Env = append(updatedContainer.Env, defaultServiceBindingRootEnv) + } updatedInitContainers = append(updatedInitContainers, *updatedContainer) } } @@ -612,6 +621,36 @@ func getWorkloadName(cavName, workloadName string) string { return fmt.Sprintf("%s-%s", cavName, strings.ToLower(workloadName)) } +func getServiceCredentialVolumeMounts(serviceInfos []v1alpha1.ServiceInfo) []corev1.VolumeMount { + volumeMounts := []corev1.VolumeMount{} + for _, serviceInfo := range serviceInfos { + volumeMounts = append(volumeMounts, corev1.VolumeMount{Name: serviceInfo.Name, MountPath: path.Join(defaultServiceBindingRootEnv.Value, serviceInfo.Name), ReadOnly: true}) + } + return volumeMounts +} + +func getServiceCredentialVolumes(serviceInfos []v1alpha1.ServiceInfo) []corev1.Volume { + volumes := []corev1.Volume{} + for _, serviceInfo := range serviceInfos { + volumes = append(volumes, corev1.Volume{Name: serviceInfo.Name, VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: serviceInfo.Secret}}}) + } + return volumes +} + +func useVolumeMountsForServiceCredentials(cav *v1alpha1.CAPApplicationVersion) bool { + value, exists := cav.Annotations[AnnotationUseCredentialVolumeMount] + return exists && value == "true" +} + +func updateServiceBindingRootEnv(envVars []corev1.EnvVar) []corev1.EnvVar { + if envIndex := slices.IndexFunc(envVars, func(currentEnv corev1.EnvVar) bool { return currentEnv.Name == defaultServiceBindingRootEnv.Name }); envIndex > -1 { + envVars[envIndex] = defaultServiceBindingRootEnv + } else { + envVars = append(envVars, defaultServiceBindingRootEnv) + } + return envVars +} + func getRestartPolicy(restartPolicy corev1.RestartPolicy, isJob bool) corev1.RestartPolicy { if isJob && restartPolicy == "" { return corev1.RestartPolicyNever diff --git a/internal/controller/testdata/capapplicationversion/cav-use-vol-mount.yaml b/internal/controller/testdata/capapplicationversion/cav-use-vol-mount.yaml new file mode 100644 index 00000000..a3c3f768 --- /dev/null +++ b/internal/controller/testdata/capapplicationversion/cav-use-vol-mount.yaml @@ -0,0 +1,205 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPApplicationVersion +metadata: + creationTimestamp: "2022-07-18T06:13:52Z" + generation: 1 + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01 + sme.sap.com/use-credential-volume-mount: "true" + labels: + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/owner-generation: "2" + sme.sap.com/owner-identifier-hash: 1f74ae2fbff71a708786a4df4bb2ca87ec603581 + name: test-cap-01-cav-v1 + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplication + name: test-cap-01 + uid: 3c7ba7cb-dc04-4fd1-be86-3eb3a5c64a98 + resourceVersion: "11371108" + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + capApplicationInstance: test-cap-01 + registrySecrets: + - regcred + version: 1.2.3 + workloads: + - name: cap-backend-srv + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/srv/server:latest + type: CAP + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.PodIp + ports: + - name: "app-port" + port: 4004 + routerDestinationName: "srv-api" + appProtocol: http + - name: "app-tech-port" + port: 4005 + networkPolicy: "Cluster" + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4004 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4004 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 20m + memory: 50Mi + - name: app-router + consumedBTPServices: + - cap-uaa + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/approuter/approuter:latest + type: Router + volumeMounts: + - name: xsapp-vol + mountPath: /usr/app/xsapp.json + subPath: xsapp.json + env: + - name: debug + valueFrom: + configMapKeyRef: + key: someKey + name: someCM + optional: true + ports: + - name: "router-port" + port: 4000 + appProtocol: http + - name: "router-tech-port" + port: 4004 + networkPolicy: "Cluster" + - name: "router-metrics-port" + port: 4007 + networkPolicy: "Cluster" + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 20m + memory: 50Mi + nodeName: app + priorityClassName: some-prio + serviceAccountName: custom-router-sa + volumes: + - name: xsapp-vol + configMap: + name: xsapp-config + - name: log-data + emptyDir: {} + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: content-job + consumedBTPServices: + - cap-uaa + jobDefinition: + image: docker.image.repo/content/cap-content:latest + type: Content + env: + - name: SOME_VERSION + value: 0.0.1 + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: mtx-job + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + jobDefinition: + image: docker.image.repo/srv/server:latest + type: TenantOperation + - name: job-worker + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/srv/server:latest + type: Additional + env: + - name: TEST_SEC_REF + valueFrom: + secretKeyRef: + key: someKey + name: someSecret + optional: true +status: + state: Processing diff --git a/internal/controller/testdata/capapplicationversion/expected/cav-processing-use-vol-mount.yaml b/internal/controller/testdata/capapplicationversion/expected/cav-processing-use-vol-mount.yaml new file mode 100644 index 00000000..dea70468 --- /dev/null +++ b/internal/controller/testdata/capapplicationversion/expected/cav-processing-use-vol-mount.yaml @@ -0,0 +1,432 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPApplicationVersion +metadata: + creationTimestamp: "2022-07-18T06:13:52Z" + generation: 1 + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01 + sme.sap.com/use-credential-volume-mount: "true" + labels: + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/owner-generation: "2" + sme.sap.com/owner-identifier-hash: 1f74ae2fbff71a708786a4df4bb2ca87ec603581 + name: test-cap-01-cav-v1 + namespace: default + finalizers: + - "sme.sap.com/capapplicationversion" + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplication + name: test-cap-01 + uid: 3c7ba7cb-dc04-4fd1-be86-3eb3a5c64a98 + resourceVersion: "11371108" + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + capApplicationInstance: test-cap-01 + registrySecrets: + - regcred + version: 1.2.3 + workloads: + - name: cap-backend-srv + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/srv/server:latest + type: CAP + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.PodIp + ports: + - name: "app-port" + port: 4004 + routerDestinationName: "srv-api" + appProtocol: http + - name: "app-tech-port" + port: 4005 + networkPolicy: "Cluster" + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4004 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4004 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 20m + memory: 50Mi + - name: app-router + consumedBTPServices: + - cap-uaa + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/approuter/approuter:latest + type: Router + volumeMounts: + - name: xsapp-vol + mountPath: /usr/app/xsapp.json + subPath: xsapp.json + env: + - name: debug + valueFrom: + configMapKeyRef: + key: someKey + name: someCM + optional: true + ports: + - name: "router-port" + port: 4000 + appProtocol: http + - name: "router-tech-port" + port: 4004 + networkPolicy: "Cluster" + - name: "router-metrics-port" + port: 4007 + networkPolicy: "Cluster" + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 20m + memory: 50Mi + nodeName: app + priorityClassName: some-prio + serviceAccountName: custom-router-sa + volumes: + - name: xsapp-vol + configMap: + name: xsapp-config + - name: log-data + emptyDir: {} + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: content-job + consumedBTPServices: + - cap-uaa + jobDefinition: + image: docker.image.repo/content/cap-content:latest + type: Content + env: + - name: SOME_VERSION + value: 0.0.1 + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: mtx-job + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + jobDefinition: + image: docker.image.repo/srv/server:latest + type: TenantOperation + - name: job-worker + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + image: docker.image.repo/srv/server:latest + type: Additional + env: + - name: TEST_SEC_REF + valueFrom: + secretKeyRef: + key: someKey + name: someSecret + optional: true +status: + conditions: + - reason: WaitingForWorkloads + observedGeneration: 1 + status: "False" + type: Ready + observedGeneration: 1 + state: Processing +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: test-cap-01 + sme.sap.com/category: Workload + sme.sap.com/workload-name: test-cap-01-cav-v1-app-router + sme.sap.com/workload-type: Router + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "1.2.3" + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: e95e0682f33a657e75e1fc435972d19bd407ba3b + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01-cav-v1 + name: test-cap-01-cav-v1-app-router + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplicationVersion + name: test-cap-01-cav-v1 + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + selector: + matchLabels: + app: test-cap-01 + sme.sap.com/category: Workload + sme.sap.com/workload-name: test-cap-01-cav-v1-app-router + sme.sap.com/workload-type: Router + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "1.2.3" + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: e95e0682f33a657e75e1fc435972d19bd407ba3b + template: + metadata: + creationTimestamp: null + labels: + app: test-cap-01 + sme.sap.com/category: Workload + sme.sap.com/workload-name: test-cap-01-cav-v1-app-router + sme.sap.com/workload-type: Router + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "1.2.3" + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: e95e0682f33a657e75e1fc435972d19bd407ba3b + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01-cav-v1 + spec: + containers: + - env: + - name: CAPOP_APP_VERSION + value: "1.2.3" + - name: debug + valueFrom: + configMapKeyRef: + key: someKey + name: someCM + optional: true + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + - name: destinations + value: '[{"name":"srv-api","url":"http://test-cap-01-cav-v1-cap-backend-srv-svc:4004","forwardAuthToken":true}]' + image: docker.image.repo/approuter/approuter:latest + volumeMounts: + - name: xsapp-vol + mountPath: /usr/app/xsapp.json + subPath: xsapp.json + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 4000 + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 20m + memory: 50Mi + name: app-router + imagePullSecrets: + - name: regcred + nodeName: app + priorityClassName: some-prio + serviceAccountName: custom-router-sa + volumes: + - name: xsapp-vol + configMap: + name: xsapp-config + - name: log-data + emptyDir: {} + - name: cap-uaa + secret: + secretName: cap-cap-01-uaa-bind-cf + - name: cap-saas-registry + secret: + secretName: cap-cap-01-saas-bind-cf + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + - name: CAPOP_APP_VERSION + value: "1.2.3" + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + volumeMounts: + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + - name: CAPOP_APP_VERSION + value: "1.2.3" + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: test-cap-01-cav-v1-content + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplicationVersion + name: test-cap-01-cav-v1 + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + creationTimestamp: null + labels: + x4.sap.com/disable-karydia: "true" + spec: + containers: + - env: + - name: CAPOP_APP_VERSION + value: 1.2.3 + - name: SOME_VERSION + value: 0.0.1 + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + image: docker.image.repo/content/cap-content:latest + name: content-job + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + volumeMounts: + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + imagePullSecrets: + - name: regcred + restartPolicy: "Never" + volumes: + - name: cap-uaa + secret: + secretName: cap-cap-01-uaa-bind-cf diff --git a/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.expected.yaml b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.expected.yaml new file mode 100644 index 00000000..3edb7f20 --- /dev/null +++ b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.expected.yaml @@ -0,0 +1,262 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPTenantOperation +metadata: + name: test-cap-01-provider-abcd + namespace: default + generation: 1 + finalizers: + - sme.sap.com/captenantoperation + annotations: + sme.sap.com/owner-identifier: default.test-cap-01-provider + labels: + sme.sap.com/tenant-operation-type: upgrade + sme.sap.com/owner-generation: "0" + sme.sap.com/owner-identifier-hash: db1f1fd7eaeb0e6407c741b7e4b2540044bcc4ec + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: 8.9.10 + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenant + name: test-cap-01-provider +spec: + tenantId: tenant-id-for-provider + subDomain: my-provider + operation: upgrade + capApplicationVersionInstance: test-cap-01-cav-v2 + steps: + - name: custom-say + type: CustomTenantOperation + - name: ten-op + type: TenantOperation + - name: custom-say + type: CustomTenantOperation +status: + state: Processing + observedGeneration: 1 + conditions: + - type: Ready + status: "False" + observedGeneration: 1 + reason: StepInitiated + message: "step 1/3 : job default.test-cap-01-provider-custom-say-gen created" + currentStep: 1 + activeJob: "test-cap-01-provider-custom-say-gen" +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + sidecar.istio.io/inject: "false" + sme.sap.com/owner-identifier: default.test-cap-01-provider-abcd + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + labels: + sme.sap.com/tenant-operation-step: "1" + sme.sap.com/tenant-operation-type: upgrade + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: ce6bb3ae0b5ebbd0116259415ccac00bff0dc431 + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + app: test-cap-01 + sme.sap.com/category: "Workload" + sme.sap.com/workload-name: "custom-say" + sme.sap.com/workload-type: "CustomTenantOperation" + generateName: test-cap-01-provider-custom-say- + name: test-cap-01-provider-custom-say-gen + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenantOperation + name: test-cap-01-provider-abcd +spec: + backoffLimit: 1 + ttlSecondsAfterFinished: 150 + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + sme.sap.com/owner-identifier: default.test-cap-01-provider-abcd + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + labels: + sme.sap.com/tenant-operation-step: "1" + sme.sap.com/tenant-operation-type: upgrade + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: ce6bb3ae0b5ebbd0116259415ccac00bff0dc431 + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + app: test-cap-01 + sme.sap.com/category: "Workload" + sme.sap.com/workload-name: "custom-say" + sme.sap.com/workload-type: "CustomTenantOperation" + spec: + containers: + - env: + - name: CAPOP_APP_VERSION + value: 8.9.10 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: upgrade + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: close + value: encounter + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + securityContext: + runAsUser: 1000 + runAsGroup: 2000 + image: docker/whalesay + volumeMounts: + - mountPath: /cache + name: cache-vol + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + command: ["cowsay", "$(CAPOP_TENANT_OPERATION)", "$(CAPOP_TENANT_ID)"] + name: custom-say + imagePullSecrets: + - name: regcred + securityContext: + runAsUser: 2000 + runAsGroup: 2000 + nodeSelector: + disktype: ssd + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: topology.kubernetes.io/zone + operator: In + values: + - antarctica-east1 + - antarctica-west1 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: someZone + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + foo: bar + matchLabelKeys: + - dummy-test-1.27 + tolerations: + - key: "test" + operator: "Equal" + value: "foo" + effect: "NoExecute" + tolerationSeconds: 300 + - key: "never-exec" + operator: "Equal" + value: "noexec" + effect: "NoExecute" + nodeName: foo + priorityClassName: prio + volumes: + - name: cache-vol + emptyDir: + sizeLimit: 500Mi + - name: log-data + emptyDir: {} + - name: cap-uaa + secret: + secretName: cap-cap-01-uaa-bind-cf + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + volumeMounts: + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + - name: CAPOP_APP_VERSION + value: 8.9.10 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: upgrade + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + - name: CAPOP_APP_VERSION + value: 8.9.10 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: upgrade + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + serviceAccountName: custom-op-sa + restartPolicy: Never diff --git a/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.initial.yaml b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.initial.yaml new file mode 100644 index 00000000..ce7a09bf --- /dev/null +++ b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount-custom.initial.yaml @@ -0,0 +1,38 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPTenantOperation +metadata: + name: test-cap-01-provider-abcd + namespace: default + generation: 1 + finalizers: + - sme.sap.com/captenantoperation + annotations: + sme.sap.com/owner-identifier: "default.test-cap-01-provider" + labels: + sme.sap.com/tenant-operation-type: upgrade + sme.sap.com/owner-generation: "0" + sme.sap.com/owner-identifier-hash: db1f1fd7eaeb0e6407c741b7e4b2540044bcc4ec + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "8.9.10" + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenant + name: test-cap-01-provider +spec: + tenantId: tenant-id-for-provider + subDomain: my-provider + operation: upgrade + capApplicationVersionInstance: test-cap-01-cav-v2 + steps: + - name: custom-say + type: CustomTenantOperation + - name: ten-op + type: TenantOperation + - name: custom-say + type: CustomTenantOperation +status: + state: Processing + conditions: [] + currentStep: 1 diff --git a/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.expected.yaml b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.expected.yaml new file mode 100644 index 00000000..28641f82 --- /dev/null +++ b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.expected.yaml @@ -0,0 +1,303 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPTenantOperation +metadata: + name: test-cap-01-provider-abcd + namespace: default + generation: 1 + finalizers: + - sme.sap.com/captenantoperation + annotations: + sme.sap.com/owner-identifier: default.test-cap-01-provider + sme.sap.com/subscription-context-secret: test-cap-01-gen + labels: + sme.sap.com/tenant-operation-type: provisioning + sme.sap.com/owner-generation: "0" + sme.sap.com/owner-identifier-hash: db1f1fd7eaeb0e6407c741b7e4b2540044bcc4ec + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "5.6.7" + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenant + name: test-cap-01-provider +spec: + tenantId: tenant-id-for-provider + subDomain: my-provider + operation: provisioning + capApplicationVersionInstance: test-cap-01-cav-v1 + steps: + - name: mtx + type: TenantOperation +status: + state: Processing + observedGeneration: 1 + conditions: + - type: Ready + status: "False" + observedGeneration: 1 + reason: StepInitiated + message: "step 1/1 : job default.test-cap-01-provider-mtx-gen created" + currentStep: 1 + activeJob: "test-cap-01-provider-mtx-gen" +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + sidecar.istio.io/inject: "false" + sme.sap.com/owner-identifier: default.test-cap-01-provider-abcd + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + labels: + sme.sap.com/tenant-operation-step: "1" + sme.sap.com/tenant-operation-type: provisioning + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: ce6bb3ae0b5ebbd0116259415ccac00bff0dc431 + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + app: test-cap-01 + sme.sap.com/category: "Workload" + sme.sap.com/workload-name: "mtx" + sme.sap.com/workload-type: "TenantOperation" + generateName: test-cap-01-provider-mtx- + name: test-cap-01-provider-mtx-gen + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenantOperation + name: test-cap-01-provider-abcd +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + sme.sap.com/owner-identifier: default.test-cap-01-provider-abcd + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + labels: + sme.sap.com/tenant-operation-step: "1" + sme.sap.com/tenant-operation-type: provisioning + sme.sap.com/owner-generation: "1" + sme.sap.com/owner-identifier-hash: ce6bb3ae0b5ebbd0116259415ccac00bff0dc431 + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + app: test-cap-01 + sme.sap.com/category: "Workload" + sme.sap.com/workload-name: "mtx" + sme.sap.com/workload-type: "TenantOperation" + spec: + containers: + - env: + - name: CAPOP_APP_VERSION + value: 5.6.7 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: provisioning + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: CAPOP_SUBSCRIPTION_PAYLOAD + valueFrom: + secretKeyRef: + name: test-cap-01-gen + key: subscriptionContext + - name: CAPOP_TENANT_MTXS_OPERATION + value: subscribe + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + volumeMounts: + - mountPath: /cache + name: cache-vol + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + - name: cap-service-manager + readOnly: true + mountPath: "/etc/secrets/cap-service-manager" + command: ["node", "./node_modules/@sap/cds-mtxs/bin/cds-mtx"] + args: ["$(CAPOP_TENANT_MTXS_OPERATION)", "tenant-id-for-provider", "--body", "$(CAPOP_SUBSCRIPTION_PAYLOAD)"] + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + cpu: 20m + memory: 20Mi + securityContext: + runAsUser: 1000 + runAsGroup: 2000 + image: docker.image.repo/srv/server:latest + name: mtx + nodeSelector: + disktype: ssd + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: topology.kubernetes.io/zone + operator: In + values: + - antarctica-east1 + - antarctica-west1 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: someZone + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + foo: bar + matchLabelKeys: + - dummy-test-1.27 + tolerations: + - key: "test" + operator: "Equal" + value: "foo" + effect: "NoExecute" + tolerationSeconds: 300 + - key: "never-exec" + operator: "Equal" + value: "noexec" + effect: "NoExecute" + imagePullSecrets: + - name: regcred + volumes: + - name: cache-vol + emptyDir: + sizeLimit: 500Mi + - name: log-data + emptyDir: {} + - name: cap-uaa + secret: + secretName: cap-cap-01-uaa-bind-cf + - name: cap-saas-registry + secret: + secretName: cap-cap-01-saas-bind-cf + - name: cap-service-manager + secret: + secretName: cap-cap-01-svc-man-bind-cf + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + volumeMounts: + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + - name: cap-service-manager + readOnly: true + mountPath: "/etc/secrets/cap-service-manager" + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + - name: CAPOP_APP_VERSION + value: 5.6.7 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: provisioning + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: CAPOP_SUBSCRIPTION_PAYLOAD + valueFrom: + secretKeyRef: + name: test-cap-01-gen + key: subscriptionContext + - name: CAPOP_TENANT_MTXS_OPERATION + value: subscribe + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + - name: cap-uaa + readOnly: true + mountPath: "/etc/secrets/cap-uaa" + - name: cap-saas-registry + readOnly: true + mountPath: "/etc/secrets/cap-saas-registry" + - name: cap-service-manager + readOnly: true + mountPath: "/etc/secrets/cap-service-manager" + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + - name: CAPOP_APP_VERSION + value: 5.6.7 + - name: CAPOP_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_TENANT_OPERATION + value: provisioning + - name: CAPOP_TENANT_SUBDOMAIN + value: my-provider + - name: CAPOP_TENANT_TYPE + value: provider + - name: CAPOP_APP_NAME + value: test-cap-01 + - name: CAPOP_GLOBAL_ACCOUNT_ID + value: btp-glo-acc-id + - name: CAPOP_PROVIDER_TENANT_ID + value: tenant-id-for-provider + - name: CAPOP_PROVIDER_SUBDOMAIN + value: my-provider + - name: CAPOP_SUBSCRIPTION_PAYLOAD + valueFrom: + secretKeyRef: + name: test-cap-01-gen + key: subscriptionContext + - name: CAPOP_TENANT_MTXS_OPERATION + value: subscribe + - name: SERVICE_BINDING_ROOT + value: "/etc/secrets" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + serviceAccountName: custom-op-sa + restartPolicy: Never diff --git a/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.initial.yaml b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.initial.yaml new file mode 100644 index 00000000..3c5eb35b --- /dev/null +++ b/internal/controller/testdata/captenantoperation/ctop-use-vol-mount.initial.yaml @@ -0,0 +1,34 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPTenantOperation +metadata: + name: test-cap-01-provider-abcd + namespace: default + generation: 1 + finalizers: + - sme.sap.com/captenantoperation + annotations: + sme.sap.com/owner-identifier: default.test-cap-01-provider + labels: + sme.sap.com/tenant-operation-type: provisioning + sme.sap.com/owner-generation: "0" + sme.sap.com/owner-identifier-hash: db1f1fd7eaeb0e6407c741b7e4b2540044bcc4ec + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/cav-version: "5.6.7" + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPTenant + name: test-cap-01-provider +spec: + tenantId: tenant-id-for-provider + subDomain: my-provider + operation: provisioning + capApplicationVersionInstance: test-cap-01-cav-v1 + steps: + - name: mtx + type: TenantOperation +status: + state: Processing + conditions: [] + currentStep: 1 diff --git a/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount-custom.yaml b/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount-custom.yaml new file mode 100644 index 00000000..95fe5e1d --- /dev/null +++ b/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount-custom.yaml @@ -0,0 +1,183 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPApplicationVersion +metadata: + generation: 1 + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01 + sme.sap.com/use-credential-volume-mount: "true" + labels: + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/owner-generation: "2" + sme.sap.com/owner-identifier-hash: 1f74ae2fbff71a708786a4df4bb2ca87ec603581 + name: test-cap-01-cav-v2 + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplication + name: test-cap-01 + uid: 3c7ba7cb-dc04-4fd1-be86-3eb3a5c64a98 + resourceVersion: "11371108" + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + capApplicationInstance: test-cap-01 + version: 8.9.10 + registrySecrets: + - regcred + workloads: + - name: cap-backend + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + type: CAP + image: docker.image.repo/srv/server:v2 + env: + - name: foo + value: bar + - name: content-job + consumedBTPServices: + - cap-uaa + jobDefinition: + type: Content + image: docker.image.repo/content/cap-content:v2 + - name: app-router + consumedBTPServices: + - cap-uaa + - cap-saas-registry + deploymentDefinition: + type: Router + image: docker.image.repo/approuter/approuter:v2 + - name: ten-op + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + jobDefinition: + type: "TenantOperation" + backoffLimit: 1 + ttlSecondsAfterFinished: 150 + image: docker.image.repo/srv/server:latest + env: + - name: flow + value: glow + - name: custom-say + consumedBTPServices: + - cap-uaa + jobDefinition: + type: "CustomTenantOperation" + volumeMounts: + - mountPath: /cache + name: cache-vol + volumes: + - name: cache-vol + emptyDir: + sizeLimit: 500Mi + - name: log-data + emptyDir: {} + serviceAccountName: custom-op-sa + image: docker/whalesay + command: ["cowsay", "$(CAPOP_TENANT_OPERATION)", "$(CAPOP_TENANT_ID)"] + backoffLimit: 1 + ttlSecondsAfterFinished: 150 + securityContext: + runAsUser: 1000 + runAsGroup: 2000 + podSecurityContext: + runAsUser: 2000 + runAsGroup: 2000 + nodeSelector: + disktype: ssd + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: topology.kubernetes.io/zone + operator: In + values: + - antarctica-east1 + - antarctica-west1 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: someZone + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + foo: bar + matchLabelKeys: + - dummy-test-1.27 + tolerations: + - key: "test" + operator: "Equal" + value: "foo" + effect: "NoExecute" + tolerationSeconds: 300 + - key: "never-exec" + operator: "Equal" + value: "noexec" + effect: "NoExecute" + nodeName: foo + priorityClassName: prio + env: + - name: close + value: encounter + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ['sh', '-c', 'tail -F /log/logs.txt'] + volumeMounts: + - name: log-data + mountPath: /log + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + tenantOperations: + provisioning: + - workloadName: custom-say + - workloadName: content-job # this will be ignored + - workloadName: ten-op + upgrade: + - workloadName: custom-say + - workloadName: ten-op + - workloadName: custom-say +status: + conditions: + - lastTransitionTime: "2022-03-18T23:07:47Z" + lastUpdateTime: "2022-03-18T23:07:47Z" + reason: CreatedDeployments + status: "True" + type: Ready + observedGeneration: 1 + state: Ready diff --git a/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount.yaml b/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount.yaml new file mode 100644 index 00000000..34526468 --- /dev/null +++ b/internal/controller/testdata/common/capapplicationversion-v1-use-vol-mount.yaml @@ -0,0 +1,157 @@ +apiVersion: sme.sap.com/v1alpha1 +kind: CAPApplicationVersion +metadata: + creationTimestamp: "2022-03-18T22:14:33Z" + generation: 1 + annotations: + sme.sap.com/btp-app-identifier: btp-glo-acc-id.test-cap-01 + sme.sap.com/owner-identifier: default.test-cap-01 + sme.sap.com/use-credential-volume-mount: "true" + labels: + sme.sap.com/btp-app-identifier-hash: f20cc8aeb2003b3abc33f749a16bd53544b6bab2 + sme.sap.com/owner-generation: "2" + sme.sap.com/owner-identifier-hash: 1f74ae2fbff71a708786a4df4bb2ca87ec603581 + name: test-cap-01-cav-v1 + namespace: default + ownerReferences: + - apiVersion: sme.sap.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: CAPApplication + name: test-cap-01 + uid: 3c7ba7cb-dc04-4fd1-be86-3eb3a5c64a98 + resourceVersion: "11371108" + uid: 5e64489b-7346-4984-8617-e8c37338b3d8 +spec: + capApplicationInstance: test-cap-01 + registrySecrets: + - regcred + version: 5.6.7 + workloads: + - name: cap-backend + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + deploymentDefinition: + type: CAP + image: docker.image.repo/srv/server:latest + - name: content-job + consumedBTPServices: + - cap-uaa + jobDefinition: + type: Content + image: docker.image.repo/content/cap-content:latest + - name: mtx + consumedBTPServices: + - cap-uaa + - cap-service-manager + - cap-saas-registry + jobDefinition: + type: "TenantOperation" + volumeMounts: + - mountPath: /cache + name: cache-vol + volumes: + - name: cache-vol + emptyDir: + sizeLimit: 500Mi + - name: log-data + emptyDir: {} + serviceAccountName: custom-op-sa + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + cpu: 20m + memory: 20Mi + securityContext: + runAsUser: 1000 + runAsGroup: 2000 + nodeSelector: + disktype: ssd + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: topology.kubernetes.io/zone + operator: In + values: + - antarctica-east1 + - antarctica-west1 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: someZone + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + foo: bar + matchLabelKeys: + - dummy-test-1.27 + tolerations: + - key: "test" + operator: "Equal" + value: "foo" + effect: "NoExecute" + tolerationSeconds: 300 + - key: "never-exec" + operator: "Equal" + value: "noexec" + effect: "NoExecute" + image: docker.image.repo/srv/server:latest + initContainers: + - name: init-container + image: docker.image.repo/init-container:latest + env: + - name: INIT_CONTAINER_ENV + value: "init-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: log-container + image: docker.image.repo/log-container:latest + restartPolicy: Always + command: ["sh", "-c", "tail -F /log/logs.txt"] + volumeMounts: + - name: log-data + mountPath: /log + env: + - name: LOG_CONTAINER_ENV + value: "log-container-env" + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: app-router + consumedBTPServices: + - cap-uaa + - cap-saas-registry + deploymentDefinition: + type: Router + image: docker.image.repo/approuter/approuter:latest +status: + conditions: + - lastTransitionTime: "2022-03-18T23:07:47Z" + lastUpdateTime: "2022-03-18T23:07:47Z" + reason: CreatedDeployments + status: "True" + type: Ready + observedGeneration: 1 + state: Ready diff --git a/website/content/en/docs/usage/resources/capapplicationversion.md b/website/content/en/docs/usage/resources/capapplicationversion.md index e7667862..1a47ba6e 100644 --- a/website/content/en/docs/usage/resources/capapplicationversion.md +++ b/website/content/en/docs/usage/resources/capapplicationversion.md @@ -42,6 +42,8 @@ spec: > The `CAPApplicationVersion` resource is meant to be immutable - it's spec should not be modified once it is deployed. This is also prevented by our web-hooks which we recommend to always keep active (default). +> By default, credentials (from secrets) required to access SAP BTP services are automatically provided as the `VCAP_SERVICES` environment variable across all workloads. However, this behavior can be changed to use volume mounts by setting the annotation `sme.sap.com/use-credential-volume-mount: "true"` on the `CAPApplicationVersion` resource. When this annotation is set, the `SERVICE_BINDING_ROOT` environment variable will be injected into all the workloads, pointing to the secret path and overriding user-defined values, if any. + ### Workloads with `deploymentDefinition` ```yaml @@ -364,4 +366,4 @@ spec: > > The supported configurations is kept minimal intentionally to keep the overall API simple by considering commonly used configurations. -> Note: For `initContainers` nearly the same environment variables as the main container are made available including VCAP_SERVICES environment. \ No newline at end of file +> Note: For `initContainers` nearly the same environment variables as the main container are made available including VCAP_SERVICES environment. Additionally, if annotation `sme.sap.com/use-credential-volume-mount: "true"` is set on the `CAPApplicationVersion` resource, the environment variable `SERVICE_BINDING_ROOT` and the volume mounts for the service credentials will also be made available.