Skip to content

Commit

Permalink
Merge branch 'main' into troubleshooting
Browse files Browse the repository at this point in the history
  • Loading branch information
I065450 authored Sep 1, 2024
2 parents 6c3aeae + fa4770a commit 4899964
Show file tree
Hide file tree
Showing 23 changed files with 965 additions and 727 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM --platform=$BUILDPLATFORM golang:1.22.2-alpine as builder
FROM --platform=$BUILDPLATFORM golang:1.22.5-alpine as builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
1 change: 1 addition & 0 deletions api/common/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

const (
ManagedByBTPOperatorLabel = "services.cloud.sap.com/managed-by-sap-btp-operator"
ClusterSecretLabel = "services.cloud.sap.com/cluster-secret"

NamespaceLabel = "_namespace"
K8sNameLabel = "_k8sname"
Expand Down
1 change: 0 additions & 1 deletion api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

288 changes: 157 additions & 131 deletions config/crd/bases/services.cloud.sap.com_servicebindings.yaml

Large diffs are not rendered by default.

239 changes: 131 additions & 108 deletions config/crd/bases/services.cloud.sap.com_serviceinstances.yaml

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
Expand Down
2 changes: 0 additions & 2 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
Expand Down Expand Up @@ -51,7 +50,6 @@ webhooks:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
creationTimestamp: null
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
Expand Down
137 changes: 77 additions & 60 deletions controllers/servicebinding_controller.go

Large diffs are not rendered by default.

55 changes: 27 additions & 28 deletions controllers/serviceinstance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import (
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/controller"

servicesv1 "github.com/SAP/sap-btp-service-operator/api/v1"
v1 "github.com/SAP/sap-btp-service-operator/api/v1"
"k8s.io/apimachinery/pkg/api/meta"

"github.com/google/uuid"
Expand All @@ -53,12 +53,11 @@ import (
// ServiceInstanceReconciler reconciles a ServiceInstance object
type ServiceInstanceReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
GetSMClient func(ctx context.Context, secretResolver *utils.SecretResolver, resourceNamespace, btpAccessSecretName string) (sm.Client, error)
Config config.Config
SecretResolver *utils.SecretResolver
Recorder record.EventRecorder
Log logr.Logger
Scheme *runtime.Scheme
GetSMClient func(ctx context.Context, serviceInstance *v1.ServiceInstance) (sm.Client, error)
Config config.Config
Recorder record.EventRecorder
}

// +kubebuilder:rbac:groups=services.cloud.sap.com,resources=serviceinstances,verbs=get;list;watch;create;update;patch;delete
Expand All @@ -70,7 +69,7 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ
log := r.Log.WithValues("serviceinstance", req.NamespacedName).WithValues("correlation_id", uuid.New().String())
ctx = context.WithValue(ctx, utils.LogKey{}, log)

serviceInstance := &servicesv1.ServiceInstance{}
serviceInstance := &v1.ServiceInstance{}
if err := r.Client.Get(ctx, req.NamespacedName, serviceInstance); err != nil {
if !apierrors.IsNotFound(err) {
log.Error(err, "unable to fetch ServiceInstance")
Expand Down Expand Up @@ -123,7 +122,7 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ
log.Info(fmt.Sprintf("instance is not in final state, handling... (generation: %d, observedGen: %d", serviceInstance.Generation, serviceInstance.Status.ObservedGeneration))
serviceInstance.SetObservedGeneration(serviceInstance.Generation)

smClient, err := r.GetSMClient(ctx, r.SecretResolver, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret)
smClient, err := r.GetSMClient(ctx, serviceInstance)
if err != nil {
log.Error(err, "failed to get sm client")
return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance)
Expand Down Expand Up @@ -164,16 +163,16 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ

func (r *ServiceInstanceReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&servicesv1.ServiceInstance{}).
For(&v1.ServiceInstance{}).
WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(r.Config.RetryBaseDelay, r.Config.RetryMaxDelay)}).
Complete(r)
}

func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) {
log := utils.GetLogger(ctx)
log.Info("Creating instance in SM")
updateHashedSpecValue(serviceInstance)
_, instanceParameters, err := utils.BuildSMRequestParameters(r.Client, serviceInstance.Namespace, serviceInstance.Spec.ParametersFrom, serviceInstance.Spec.Parameters)
_, instanceParameters, err := utils.BuildSMRequestParameters(serviceInstance.Namespace, serviceInstance.Spec.ParametersFrom, serviceInstance.Spec.Parameters)
if err != nil {
// if parameters are invalid there is nothing we can do, the user should fix it according to the error message in the condition
log.Error(err, "failed to parse instance parameters")
Expand Down Expand Up @@ -223,13 +222,13 @@ func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient
return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance)
}

func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) {
log := utils.GetLogger(ctx)
log.Info(fmt.Sprintf("updating instance %s in SM", serviceInstance.Status.InstanceID))

updateHashedSpecValue(serviceInstance)

_, instanceParameters, err := utils.BuildSMRequestParameters(r.Client, serviceInstance.Namespace, serviceInstance.Spec.ParametersFrom, serviceInstance.Spec.Parameters)
_, instanceParameters, err := utils.BuildSMRequestParameters(serviceInstance.Namespace, serviceInstance.Spec.ParametersFrom, serviceInstance.Spec.Parameters)
if err != nil {
log.Error(err, "failed to parse instance parameters")
return utils.MarkAsNonTransientError(ctx, r.Client, smClientTypes.UPDATE, fmt.Sprintf("failed to parse parameters: %v", err.Error()), serviceInstance)
Expand Down Expand Up @@ -263,11 +262,11 @@ func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient
return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance)
}

func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) {
log := utils.GetLogger(ctx)

if controllerutil.ContainsFinalizer(serviceInstance, common.FinalizerName) {
smClient, err := r.GetSMClient(ctx, r.SecretResolver, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret)
smClient, err := r.GetSMClient(ctx, serviceInstance)
if err != nil {
log.Error(err, "failed to get sm client")
return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance)
Expand Down Expand Up @@ -312,7 +311,7 @@ func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceI
return ctrl.Result{}, nil
}

func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, serviceInstance *servicesv1.ServiceInstance, smClient sm.Client) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, serviceInstance *v1.ServiceInstance, smClient sm.Client) (ctrl.Result, error) {
log := utils.GetLogger(ctx)
log.Info("Handling change in instance sharing")

Expand Down Expand Up @@ -346,10 +345,10 @@ func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, s
return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance)
}

func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) {
log := utils.GetLogger(ctx)
log.Info(fmt.Sprintf("resource is in progress, found operation url %s", serviceInstance.Status.OperationURL))
smClient, err := r.GetSMClient(ctx, r.SecretResolver, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret)
smClient, err := r.GetSMClient(ctx, serviceInstance)
if err != nil {
log.Error(err, "failed to get sm client")
return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance)
Expand All @@ -360,7 +359,7 @@ func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *s
log.Info(fmt.Sprintf("failed to fetch operation, got error from SM: %s", statusErr.Error()), "operationURL", serviceInstance.Status.OperationURL)
utils.SetInProgressConditions(ctx, serviceInstance.Status.OperationType, string(smClientTypes.INPROGRESS), serviceInstance)
// if failed to read operation status we cleanup the status to trigger re-sync from SM
freshStatus := servicesv1.ServiceInstanceStatus{Conditions: serviceInstance.GetConditions(), ObservedGeneration: serviceInstance.Generation}
freshStatus := v1.ServiceInstanceStatus{Conditions: serviceInstance.GetConditions(), ObservedGeneration: serviceInstance.Generation}
if utils.IsMarkedForDeletion(serviceInstance.ObjectMeta) {
freshStatus.InstanceID = serviceInstance.Status.InstanceID
}
Expand Down Expand Up @@ -426,7 +425,7 @@ func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *s
return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance)
}

func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, serviceInstance *servicesv1.ServiceInstance, opURL string) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, serviceInstance *v1.ServiceInstance, opURL string) (ctrl.Result, error) {
serviceInstance.Status.OperationURL = opURL
serviceInstance.Status.OperationType = smClientTypes.DELETE
utils.SetInProgressConditions(ctx, smClientTypes.DELETE, "", serviceInstance)
Expand All @@ -438,7 +437,7 @@ func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, servi
return ctrl.Result{Requeue: true, RequeueAfter: r.Config.PollInterval}, nil
}

func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (*smClientTypes.ServiceInstance, error) {
func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (*smClientTypes.ServiceInstance, error) {
log := utils.GetLogger(ctx)
parameters := sm.Parameters{
FieldQuery: []string{
Expand All @@ -463,7 +462,7 @@ func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context,
return nil, nil
}

func (r *ServiceInstanceReconciler) recover(ctx context.Context, smClient sm.Client, k8sInstance *servicesv1.ServiceInstance, smInstance *smClientTypes.ServiceInstance) (ctrl.Result, error) {
func (r *ServiceInstanceReconciler) recover(ctx context.Context, smClient sm.Client, k8sInstance *v1.ServiceInstance, smInstance *smClientTypes.ServiceInstance) (ctrl.Result, error) {
log := utils.GetLogger(ctx)

log.Info(fmt.Sprintf("found existing instance in SM with id %s, updating status", smInstance.ID))
Expand Down Expand Up @@ -547,7 +546,7 @@ func (r *ServiceInstanceReconciler) handleInstanceSharingError(ctx context.Conte
return ctrl.Result{Requeue: isTransient}, utils.UpdateStatus(ctx, r.Client, object)
}

func isFinalState(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) bool {
func isFinalState(ctx context.Context, serviceInstance *v1.ServiceInstance) bool {
log := utils.GetLogger(ctx)
if utils.IsMarkedForDeletion(serviceInstance.ObjectMeta) {
log.Info("instance is not in final state, it is marked for deletion")
Expand Down Expand Up @@ -580,7 +579,7 @@ func isFinalState(ctx context.Context, serviceInstance *servicesv1.ServiceInstan
return true
}

func updateRequired(serviceInstance *servicesv1.ServiceInstance) bool {
func updateRequired(serviceInstance *v1.ServiceInstance) bool {
//update is not supported for failed instances (this can occur when instance creation was asynchronously)
if serviceInstance.Status.Ready != metav1.ConditionTrue {
return false
Expand All @@ -594,7 +593,7 @@ func updateRequired(serviceInstance *servicesv1.ServiceInstance) bool {
return getSpecHash(serviceInstance) != serviceInstance.Status.HashedSpec
}

func sharingUpdateRequired(serviceInstance *servicesv1.ServiceInstance) bool {
func sharingUpdateRequired(serviceInstance *v1.ServiceInstance) bool {
//relevant only for non-shared instances - sharing instance is possible only for usable instances
if serviceInstance.Status.Ready != metav1.ConditionTrue {
return false
Expand Down Expand Up @@ -662,7 +661,7 @@ func getTags(tags []byte) ([]string, error) {
return tagsArr, nil
}

func getSpecHash(serviceInstance *servicesv1.ServiceInstance) string {
func getSpecHash(serviceInstance *v1.ServiceInstance) string {
spec := serviceInstance.Spec
spec.Shared = ptr.To(false)
specBytes, _ := json.Marshal(spec)
Expand Down Expand Up @@ -700,7 +699,7 @@ func setSharedCondition(object common.SAPBTPResource, status metav1.ConditionSta
object.SetConditions(conditions)
}

func updateHashedSpecValue(serviceInstance *servicesv1.ServiceInstance) {
func updateHashedSpecValue(serviceInstance *v1.ServiceInstance) {
serviceInstance.Status.HashedSpec = getSpecHash(serviceInstance)
}

Expand Down
9 changes: 6 additions & 3 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ import (
"testing"
"time"

"github.com/SAP/sap-btp-service-operator/internal/utils"

"sigs.k8s.io/controller-runtime/pkg/metrics/server"

"github.com/SAP/sap-btp-service-operator/api/common"
"github.com/SAP/sap-btp-service-operator/internal/utils"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"

. "github.com/onsi/ginkgo"
Expand Down Expand Up @@ -119,6 +120,8 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())

utils.InitializeSecretsClient(k8sClient, nil, config.Config{EnableLimitedCache: false})

webhookInstallOptions := &testEnv.WebhookInstallOptions

k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Expand Down Expand Up @@ -155,7 +158,7 @@ var _ = BeforeSuite(func(done Done) {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("ServiceInstance"),
GetSMClient: func(_ context.Context, _ *utils.SecretResolver, _, _ string) (sm.Client, error) {
GetSMClient: func(_ context.Context, _ *v1.ServiceInstance) (sm.Client, error) {
return fakeClient, nil
},
Config: testConfig,
Expand All @@ -167,7 +170,7 @@ var _ = BeforeSuite(func(done Done) {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Log: ctrl.Log.WithName("controllers").WithName("ServiceBinding"),
GetSMClient: func(_ context.Context, _ *utils.SecretResolver, _, _ string) (sm.Client, error) {
GetSMClient: func(_ context.Context, _ *v1.ServiceInstance) (sm.Client, error) {
return fakeClient, nil
},
Config: testConfig,
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/SAP/sap-btp-service-operator

go 1.22.2
go 1.22.5

require (
github.com/Masterminds/sprig/v3 v3.2.3
Expand All @@ -27,6 +27,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
Expand Down
16 changes: 7 additions & 9 deletions internal/utils/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import (
servicesv1 "github.com/SAP/sap-btp-service-operator/api/v1"
corev1 "k8s.io/api/core/v1"

"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/yaml"
)

Expand All @@ -22,11 +20,11 @@ import (
// secret values.
// The second return value is parameters marshalled to byt array
// The third return value is any error that caused the function to fail.
func BuildSMRequestParameters(kubeClient client.Client, namespace string, parametersFrom []servicesv1.ParametersFromSource, parameters *runtime.RawExtension) (map[string]interface{}, []byte, error) {
func BuildSMRequestParameters(namespace string, parametersFrom []servicesv1.ParametersFromSource, parameters *runtime.RawExtension) (map[string]interface{}, []byte, error) {
params := make(map[string]interface{})
if len(parametersFrom) > 0 {
for _, p := range parametersFrom {
fps, err := fetchParametersFromSource(kubeClient, namespace, &p)
fps, err := fetchParametersFromSource(namespace, &p)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -96,9 +94,9 @@ func unmarshalJSON(in []byte) (map[string]interface{}, error) {
}

// fetchSecretKeyValue requests and returns the contents of the given secret key
func fetchSecretKeyValue(kubeClient client.Client, namespace string, secretKeyRef *servicesv1.SecretKeyReference) ([]byte, error) {
func fetchSecretKeyValue(namespace string, secretKeyRef *servicesv1.SecretKeyReference) ([]byte, error) {
secret := &corev1.Secret{}
err := kubeClient.Get(context.Background(), types.NamespacedName{Namespace: namespace, Name: secretKeyRef.Name}, secret)
err := GetSecretWithFallback(context.Background(), types.NamespacedName{Namespace: namespace, Name: secretKeyRef.Name}, secret)

if err != nil {
return nil, err
Expand All @@ -108,10 +106,10 @@ func fetchSecretKeyValue(kubeClient client.Client, namespace string, secretKeyRe

// fetchParametersFromSource fetches data from a specified external source and
// represents it in the parameters map format
func fetchParametersFromSource(kubeClient client.Client, namespace string, parametersFrom *servicesv1.ParametersFromSource) (map[string]interface{}, error) {
func fetchParametersFromSource(namespace string, parametersFrom *servicesv1.ParametersFromSource) (map[string]interface{}, error) {
var params map[string]interface{}
if parametersFrom.SecretKeyRef != nil {
data, err := fetchSecretKeyValue(kubeClient, namespace, parametersFrom.SecretKeyRef)
data, err := fetchSecretKeyValue(namespace, parametersFrom.SecretKeyRef)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/utils/parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var _ = Describe("Parameters", func() {
var parametersFrom []v1.ParametersFromSource
parameters := (*runtime.RawExtension)(nil)

params, rawParam, err := BuildSMRequestParameters(nil, "", parametersFrom, parameters)
params, rawParam, err := BuildSMRequestParameters("", parametersFrom, parameters)

Expect(err).To(BeNil())
Expect(params).To(BeNil())
Expand All @@ -25,7 +25,7 @@ var _ = Describe("Parameters", func() {
Raw: []byte(`{"key":"value"}`),
}

params, rawParam, err := BuildSMRequestParameters(nil, "", parametersFrom, parameters)
params, rawParam, err := BuildSMRequestParameters("", parametersFrom, parameters)

Expect(err).To(BeNil())
Expect(params).To(Equal(map[string]interface{}{"key": "value"}))
Expand Down
Loading

0 comments on commit 4899964

Please sign in to comment.