Skip to content

Commit

Permalink
PoC rework ensure
Browse files Browse the repository at this point in the history
  • Loading branch information
bouskaJ committed Nov 25, 2024
1 parent 799b514 commit 7ee3818
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 121 deletions.
24 changes: 24 additions & 0 deletions internal/controller/common/action/base_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import (
"strings"
"time"

"github.com/securesign/operator/internal/apis"
"github.com/securesign/operator/internal/controller/annotations"
"github.com/securesign/operator/internal/controller/constants"
"k8s.io/apimachinery/pkg/api/equality"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

Expand Down Expand Up @@ -62,6 +65,7 @@ func (action *BaseAction) StatusUpdate(ctx context.Context, obj client2.Object)
return &Result{Result: reconcile.Result{Requeue: false}}
}

// Deprecated: Use Error function
func (action *BaseAction) Failed(err error) *Result {
action.Logger.Error(err, "error during action execution")
return &Result{
Expand All @@ -70,6 +74,25 @@ func (action *BaseAction) Failed(err error) *Result {
}
}

func (action *BaseAction) Error(ctx context.Context, err error, instance apis.ConditionsAwareObject) *Result {
if errors.Is(err, reconcile.TerminalError(err)) {
instance.SetCondition(metav1.Condition{
Type: constants.Ready,
Status: metav1.ConditionFalse,
Reason: constants.Failure,
Message: err.Error(),
})
if updateErr := action.Client.Status().Update(ctx, instance); updateErr != nil {
err = errors.Join(err, updateErr)
}
}
action.Logger.Error(err, "error during action execution")
return &Result{
Err: err,
}
}

// Deprecated: Use Error function with TerminalError passed as an argument
func (action *BaseAction) FailedWithStatusUpdate(ctx context.Context, err error, instance client2.Object) *Result {
if e := action.Client.Status().Update(ctx, instance); e != nil {
if strings.Contains(err.Error(), OptimisticLockErrorMsg) {
Expand All @@ -96,6 +119,7 @@ func (action *BaseAction) Requeue() *Result {
}
}

// Deprecated: Use kubernetes.CreateOrUpdate function
func (action *BaseAction) Ensure(ctx context.Context, obj client2.Object, opts ...EnsureOption) (bool, error) {
var (
expected client2.Object
Expand Down
27 changes: 27 additions & 0 deletions internal/controller/common/utils/kubernetes/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import (
"strconv"
"strings"

"github.com/securesign/operator/internal/controller/annotations"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
k8sLabels "k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

v13 "github.com/openshift/api/operator/v1"
"github.com/securesign/operator/internal/controller/common/utils"
Expand Down Expand Up @@ -133,3 +137,26 @@ func FindByLabelSelector(ctx context.Context, c client.Client, list client.Objec

return c.List(ctx, list, client.InNamespace(namespace), listOptions)
}

func CreateOrUpdate[T client.Object](ctx context.Context, cli client.Client, obj T, fn ...func(object T) error) (result controllerutil.OperationResult, err error) {
err = retry.OnError(retry.DefaultRetry, func(err error) bool {
return apiErrors.IsConflict(err) || apiErrors.IsAlreadyExists(err)
}, func() error {
var createUpdateError error
result, createUpdateError = controllerutil.CreateOrUpdate(ctx, cli, obj, func() (fnError error) {
annoStr, find := obj.GetAnnotations()[annotations.PausedReconciliation]
if find {
annoBool, _ := strconv.ParseBool(annoStr)
if annoBool {
return
}
}
for _, f := range fn {
fnError = errors.Join(fnError, f(obj))
}
return
})
return createUpdateError
})
return
}
18 changes: 18 additions & 0 deletions internal/controller/common/utils/kubernetes/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,21 @@ func getDeploymentCondition(status v1.DeploymentStatus, condType v1.DeploymentCo
}
return nil
}

func FindContainerByName(dp *v1.Deployment, containerName string) *corev1.Container {
for i, c := range dp.Spec.Template.Spec.Containers {
if c.Name == containerName {
return &dp.Spec.Template.Spec.Containers[i]
}
}
return nil
}

func FindVolumeByName(dp *v1.Deployment, volumeName string) *corev1.Volume {
for i, v := range dp.Spec.Template.Spec.Volumes {
if v.Name == volumeName {
return &dp.Spec.Template.Spec.Volumes[i]
}
}
return nil
}
45 changes: 45 additions & 0 deletions internal/controller/common/utils/kubernetes/ensure/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ensure

import (
"slices"

"golang.org/x/exp/maps"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func managedDeleteFunction(managed []string) func(string, string) bool {
return func(key, _ string) bool {
return slices.Contains(managed, key)
}
}

func Labels[T client.Object](managedLabels []string, labels map[string]string) func(controlled T) error {
return func(obj T) (e error) {
if obj.GetLabels() == nil {
obj.SetLabels(labels)
return
}
maps.DeleteFunc(obj.GetLabels(), managedDeleteFunction(managedLabels))
maps.Copy(obj.GetLabels(), labels)
return
}
}

func Annotations[T client.Object](managedAnnotations []string, annotations map[string]string) func(controlled T) error {
return func(obj T) (e error) {
if obj.GetAnnotations() == nil {
obj.SetAnnotations(annotations)
return
}
maps.DeleteFunc(obj.GetAnnotations(), managedDeleteFunction(managedAnnotations))
maps.Copy(obj.GetAnnotations(), annotations)
return
}
}

func ControllerReference[T client.Object](owner client.Object, cli client.Client) func(controlled T) error {
return func(controlled T) error {
return controllerutil.SetControllerReference(owner, controlled, cli.Scheme())
}
}
13 changes: 13 additions & 0 deletions internal/controller/common/utils/kubernetes/ensure/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ensure

import (
"github.com/securesign/operator/internal/controller/common/utils"
v1 "k8s.io/api/apps/v1"
)

func Proxy() func(*v1.Deployment) error {
return func(dp *v1.Deployment) error {
utils.SetProxyEnvs(dp)
return nil
}
}
21 changes: 20 additions & 1 deletion internal/controller/common/utils/set_proxy.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
package utils

import (
"reflect"
"slices"

"github.com/operator-framework/operator-lib/proxy"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
)

// SetProxyEnvs set the standard environment variables for proxys "HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY"
func SetProxyEnvs(dep *appsv1.Deployment) {
proxyEnvs := proxy.ReadProxyVarsFromEnv()
for i, container := range dep.Spec.Template.Spec.Containers {
dep.Spec.Template.Spec.Containers[i].Env = append(container.Env, proxy.ReadProxyVarsFromEnv()...)
for _, e := range proxyEnvs {
if index := slices.IndexFunc(container.Env,
func(envVar v1.EnvVar) bool { return e.Name == envVar.Name },
); index > -1 {
if reflect.DeepEqual(e, container.Env[index]) {
// variable already present
continue
} else {
// overwrite
dep.Spec.Template.Spec.Containers[i].Env[index] = e
}
} else {
dep.Spec.Template.Spec.Containers[i].Env = append(dep.Spec.Template.Spec.Containers[i].Env, e)
}
}
}
}
19 changes: 15 additions & 4 deletions internal/controller/common/utils/set_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"testing"

. "github.com/onsi/gomega"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
)
Expand All @@ -28,6 +27,10 @@ func TestSetProxyEnvs(t *testing.T) {
Name: "answer",
Value: "42",
},
{
Name: "no_proxy",
Value: "toBeOverwritten",
},
}

// Define a mock deployment
Expand All @@ -49,7 +52,7 @@ func TestSetProxyEnvs(t *testing.T) {
SetProxyEnvs(dep)

g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeNil())
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(HaveLen(1))
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(HaveLen(2))
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(BeEquivalentTo(defaultEnv))

for _, e := range mockReadProxyVarsFromEnv() {
Expand All @@ -58,9 +61,17 @@ func TestSetProxyEnvs(t *testing.T) {

SetProxyEnvs(dep)

expectedEnvVars := append(defaultEnv, mockReadProxyVarsFromEnv()...)
expectedEnvVars := append(mockReadProxyVarsFromEnv(), corev1.EnvVar{
Name: "answer",
Value: "42",
})

g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeNil())
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(HaveLen(7))
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(BeEquivalentTo(expectedEnvVars))
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(ConsistOf(expectedEnvVars))

// ensure no duplicates
SetProxyEnvs(dep)
g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeNil())
g.Expect(dep.Spec.Template.Spec.Containers[0].Env).Should(HaveLen(7))
}
Loading

0 comments on commit 7ee3818

Please sign in to comment.