Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/v1alpha1/dvlssecret_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ type DvlsSecretSpec struct {
type DvlsSecretStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
EntryModifiedDate metav1.Time `json:"entryModifiedDate"`
}

//+kubebuilder:object:root=true
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

5 changes: 5 additions & 0 deletions config/crd/bases/dvls.devolutions.com_dvlssecrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ spec:
- type
type: object
type: array
entryModifiedDate:
format: date-time
type: string
required:
- entryModifiedDate
type: object
type: object
served: true
Expand Down
14 changes: 13 additions & 1 deletion config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ spec:
control-plane: controller-manager
spec:
# TODO(user): Uncomment the following code to configure the nodeAffinity expression
# according to the platforms which are supported by your solution.
# according to the platforms which are supported by your solution.
# It is considered best practice to support multiple architectures. You can
# build your manager image using the makefile target docker-buildx.
# affinity:
Expand Down Expand Up @@ -98,5 +98,17 @@ spec:
requests:
cpu: 10m
memory: 64Mi
env:
- name: DEVO_OPERATOR_DVLS_APPID
value: "00000000-0000-0000-0000-000000000000"
- name: DEVO_OPERATOR_DVLS_BASEURI
value: "https://your-dvls-instance.com"
- name: DEVO_OPERATOR_REQUEUE_DURATION
value: 60s
- name: DEVO_OPERATOR_DVLS_APPSECRET
valueFrom:
secretKeyRef:
key: secret
name: appid
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
95 changes: 55 additions & 40 deletions controllers/dvlssecret_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package controllers
import (
"context"
"fmt"
"reflect"
"time"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -87,8 +86,9 @@ func (r *DvlsSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, fmt.Errorf("failed to get DvlsSecret object, %w", err)
}

if dvlsSecret.Status.Conditions == nil || len(dvlsSecret.Status.Conditions) == 0 {
if dvlsSecret.Status.Conditions == nil || len(dvlsSecret.Status.Conditions) == 0 || dvlsSecret.Status.EntryModifiedDate.IsZero() {
meta.SetStatusCondition(&dvlsSecret.Status.Conditions, v1.Condition{Type: statusAvailableDvlsSecret, Status: v1.ConditionUnknown, Reason: "Reconciling"})
dvlsSecret.Status.EntryModifiedDate = v1.Date(0001, time.January, 1, 1, 1, 1, 1, time.UTC)
if err := r.Status().Update(ctx, dvlsSecret); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to update DvlsSecret status, %w", err)
}
Expand Down Expand Up @@ -118,7 +118,26 @@ func (r *DvlsSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, nil
}

secret, err := DvlsClient.GetSecret(dvlsSecret.Spec.EntryID)
kSecret := &corev1.Secret{}
err = r.Get(ctx, req.NamespacedName, kSecret)
if err != nil && !apierrors.IsNotFound(err) {
return ctrl.Result{}, fmt.Errorf("failed to get kubernetes secret object, %w", err)
}
kSecretNotFound := apierrors.IsNotFound(err)

var entryTime, secretTime time.Time
if !dvlsSecret.Status.EntryModifiedDate.IsZero() && entry.ModifiedDate != nil {
secretTime = dvlsSecret.Status.EntryModifiedDate.Time
entryTime = entry.ModifiedDate.Time
}

if entryTime.Equal(secretTime) && !kSecretNotFound {
return ctrl.Result{
RequeueAfter: RequeueDuration,
}, nil
}

secret, err := DvlsClient.GetEntryCredentialsPassword(entry)
if err != nil {
log.Error(err, "unable to fetch dvls secret", "entryId", dvlsSecret.Spec.EntryID)
meta.SetStatusCondition(&dvlsSecret.Status.Conditions, v1.Condition{Type: statusDegradedDvlsSecret, Status: v1.ConditionTrue, Reason: "Reconciling", Message: "Unable to fetch secret on DVLS instance"})
Expand All @@ -129,34 +148,32 @@ func (r *DvlsSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
secretMap := make(map[string]string)
secretMap["entry-id"] = secret.ID
secretMap["username"] = secret.Username
secretMap["password"] = secret.Password
secretMap["entry-name"] = secret.EntryName
secretMap["username"] = secret.Credentials.Username
if secret.Credentials.Password != nil {
secretMap["password"] = *secret.Credentials.Password
}

kSecret := &corev1.Secret{}
err = r.Get(ctx, req.NamespacedName, kSecret)
if err != nil {
if apierrors.IsNotFound(err) {
log.Info("Kubernetes secret not found, creating")
kSecret.ObjectMeta = v1.ObjectMeta{
Name: req.Name,
Namespace: req.Namespace,
}
err := ctrl.SetControllerReference(dvlsSecret, kSecret, r.Scheme)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to set kubernetes secret owner, %w", err)
}

kSecret.Type = corev1.SecretType(dvlsSecretType)
kSecret.StringData = secretMap

err = r.Create(ctx, kSecret)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to create kubernetes secret, %w", err)
}
if kSecretNotFound {
log.Info("Kubernetes secret not found, creating")
kSecret.ObjectMeta = v1.ObjectMeta{
Name: req.Name,
Namespace: req.Namespace,
}
err := ctrl.SetControllerReference(dvlsSecret, kSecret, r.Scheme)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to set kubernetes secret owner, %w", err)
}

return ctrl.Result{}, nil
kSecret.Type = corev1.SecretType(dvlsSecretType)
kSecret.StringData = secretMap

err = r.Create(ctx, kSecret)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to create kubernetes secret, %w", err)
}
return ctrl.Result{}, fmt.Errorf("failed to get kubernetes secret object, %w", err)

return ctrl.Result{}, nil
}

var owned bool
Expand All @@ -171,23 +188,21 @@ func (r *DvlsSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, fmt.Errorf("found existing kubernetes secret with name %s in namespace %s but is either not the correct type or not owned by the DvlsSecret resource. Either delete the existing secret or use a different name", kSecret.GetName(), kSecret.GetNamespace())
}

kSecretDataMapString := make(map[string]string)
for k, v := range kSecret.Data {
kSecretDataMapString[k] = string(v)
kSecret.StringData = secretMap
err = r.Update(ctx, kSecret)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to get update kubernetes secret object, %w", err)
}

if !reflect.DeepEqual(kSecretDataMapString, secretMap) {
kSecret.StringData = secretMap
err := r.Update(ctx, kSecret)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to get update kubernetes secret object, %w", err)
}

log.Info("updated secret")
log.Info("updated secret")
err = r.Get(ctx, req.NamespacedName, dvlsSecret)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to get DvlsSecret object, %w", err)
}

meta.SetStatusCondition(&dvlsSecret.Status.Conditions, v1.Condition{Type: statusAvailableDvlsSecret, Status: v1.ConditionTrue, Reason: "Reconciling"})
meta.RemoveStatusCondition(&dvlsSecret.Status.Conditions, statusDegradedDvlsSecret)
dvlsSecret.Status.EntryModifiedDate = v1.NewTime(entryTime)

if err := r.Status().Update(ctx, dvlsSecret); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to update DvlsSecret status, %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/Devolutions/devolutions-kubernetes-operator
go 1.19

require (
github.com/Devolutions/go-dvls v0.2.0
github.com/Devolutions/go-dvls v0.4.0
github.com/onsi/ginkgo/v2 v2.4.0
github.com/onsi/gomega v1.23.0
k8s.io/api v0.26.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Devolutions/go-dvls v0.2.0 h1:es+PdbFiz2EsrgyaTRMa5AvlUVRKBl9fxyC16jpclWA=
github.com/Devolutions/go-dvls v0.2.0/go.mod h1:LWmMkJugG1/aUH5oXwHN13EvJC+YhvyKH/11pPecPtw=
github.com/Devolutions/go-dvls v0.4.0 h1:7zNbQ2LtfDIVTGiqVP3qntGPJCEadkgDXVaf0eIWdEI=
github.com/Devolutions/go-dvls v0.4.0/go.mod h1:LWmMkJugG1/aUH5oXwHN13EvJC+YhvyKH/11pPecPtw=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
Expand Down
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ func main() {
os.Exit(1)
}

dvlsClient, dvlsUser, err := dvls.NewClient(appId, appSecret, dvlsBaseUri)
dvlsClient, err := dvls.NewClient(appId, appSecret, dvlsBaseUri)
if err != nil {
setupLog.Error(err, "unable to set up dvls client")
os.Exit(1)
}

if dvlsUser.UserType != dvls.UserAuthenticationApplication {
setupLog.Error(nil, "provided credentials are not for an Application user type", "userType", dvlsUser.UserType)
if dvlsClient.ClientUser.UserType != dvls.UserAuthenticationApplication {
setupLog.Error(nil, "provided credentials are not for an Application user type", "userType", dvlsClient.ClientUser.UserType)
os.Exit(1)
}

Expand Down