Skip to content

Commit

Permalink
feat(lifecycle-operator): introduce functions for SchedulingGates fun…
Browse files Browse the repository at this point in the history
…ctionality (#2140)

Signed-off-by: odubajDT <ondrej.dubaj@dynatrace.com>
Signed-off-by: odubajDT <93584209+odubajDT@users.noreply.github.com>
Co-authored-by: Florian Bacher <florian.bacher@dynatrace.com>
Co-authored-by: RealAnna <89971034+RealAnna@users.noreply.github.com>
Co-authored-by: Giovanni Liva <giovanni.liva@dynatrace.com>
  • Loading branch information
4 people authored Sep 26, 2023
1 parent 84ae464 commit b40503e
Show file tree
Hide file tree
Showing 15 changed files with 1,030 additions and 46 deletions.
10 changes: 6 additions & 4 deletions lifecycle-operator/apis/lifecycle/v1alpha3/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ const K8sRecommendedAppAnnotations = "app.kubernetes.io/part-of"
const K8sRecommendedManagedByAnnotations = "app.kubernetes.io/managed-by"
const PreDeploymentEvaluationAnnotation = "keptn.sh/pre-deployment-evaluations"
const PostDeploymentEvaluationAnnotation = "keptn.sh/post-deployment-evaluations"
const SchedulingGateRemoved = "keptn.sh/scheduling-gate-removed"
const TaskNameAnnotation = "keptn.sh/task-name"
const NamespaceEnabledAnnotation = "keptn.sh/lifecycle-toolkit"
const CreateAppTaskSpanName = "create_%s_app_task"
const CreateWorkloadTaskSpanName = "create_%s_deployment_task"
const CreateAppEvalSpanName = "create_%s_app_evaluation"
const CreateWorkloadEvalSpanName = "create_%s_deployment_evaluation"
const AppTypeAnnotation = "keptn.sh/app-type"
const KeptnGate = "keptn-prechecks-gate"

const MinKLTNameLen = 80
const MinKeptnNameLen = 80
const MaxK8sObjectLength = 253

type AppType string
Expand Down Expand Up @@ -176,17 +178,17 @@ const (

func GenerateTaskName(checkType CheckType, taskName string) string {
randomId := rand.Intn(99_999-10_000) + 10000
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKLTNameLen, string(checkType), taskName, strconv.Itoa(randomId))
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKeptnNameLen, string(checkType), taskName, strconv.Itoa(randomId))
}

func GenerateJobName(taskName string) string {
randomId := rand.Intn(99_999-10_000) + 10000
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKLTNameLen, taskName, strconv.Itoa(randomId))
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKeptnNameLen, taskName, strconv.Itoa(randomId))
}

func GenerateEvaluationName(checkType CheckType, evalName string) string {
randomId := rand.Intn(99_999-10_000) + 10000
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKLTNameLen, string(checkType), evalName, strconv.Itoa(randomId))
return operatorcommon.CreateResourceName(MaxK8sObjectLength, MinKeptnNameLen, string(checkType), evalName, strconv.Itoa(randomId))
}

// MergeMaps merges two maps into a new map. If a key exists in both maps, the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func init() {
}

func (a KeptnApp) GetAppVersionName() string {
return operatorcommon.CreateResourceName(common.MaxK8sObjectLength, common.MinKLTNameLen, a.Name, a.Spec.Version, common.Hash(a.Generation))
return operatorcommon.CreateResourceName(common.MaxK8sObjectLength, common.MinKeptnNameLen, a.Name, a.Spec.Version, common.Hash(a.Generation))
}

func (a KeptnApp) SetSpanAttributes(span trace.Span) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func init() {
}

func (w KeptnWorkload) GetWorkloadInstanceName() string {
return operatorcommon.CreateResourceName(common.MaxK8sObjectLength, common.MinKLTNameLen, w.Name, w.Spec.Version)
return operatorcommon.CreateResourceName(common.MaxK8sObjectLength, common.MinKeptnNameLen, w.Name, w.Spec.Version)
}

func (w KeptnWorkload) SetSpanAttributes(span trace.Span) {
Expand Down
1 change: 1 addition & 0 deletions lifecycle-operator/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ rules:
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
Expand Down

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

108 changes: 108 additions & 0 deletions lifecycle-operator/controllers/common/schedulinggateshandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package common

import (
"context"

"github.com/go-logr/logr"
klcv1alpha3 "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3"
apicommon "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3/common"
controllererrors "github.com/keptn/lifecycle-toolkit/lifecycle-operator/controllers/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

//go:generate moq -pkg fake -skip-ensure -out ./fake/schedulinggateshandler_mock.go . ISchedulingGatesHandler
type ISchedulingGatesHandler interface {
RemoveGates(ctx context.Context, workloadInstance *klcv1alpha3.KeptnWorkloadInstance) error
Enabled() bool
}

type RemoveGatesFunc func(ctx context.Context, c client.Client, podName string, podNamespace string) error
type GetPodsFunc func(ctx context.Context, c client.Client, ownerUID types.UID, ownerKind string, namespace string) ([]string, error)

type SchedulingGatesHandler struct {
client.Client
logr.Logger
enabled bool
removeGates RemoveGatesFunc
getPods GetPodsFunc
}

func NewSchedulingGatesHandler(c client.Client, l logr.Logger, enabled bool) *SchedulingGatesHandler {
return &SchedulingGatesHandler{
Client: c,
Logger: l,
enabled: enabled,
removeGates: removePodGates,
getPods: getPodsOfOwner,
}
}

func (h *SchedulingGatesHandler) RemoveGates(ctx context.Context, workloadInstance *klcv1alpha3.KeptnWorkloadInstance) error {
switch workloadInstance.Spec.ResourceReference.Kind {
case "Pod":
return h.removeGates(ctx, h.Client, workloadInstance.Spec.ResourceReference.Name, workloadInstance.Namespace)
case "ReplicaSet", "StatefulSet", "DaemonSet":
podList, err := h.getPods(ctx, h.Client, workloadInstance.Spec.ResourceReference.UID, workloadInstance.Spec.ResourceReference.Kind, workloadInstance.Namespace)
if err != nil {
h.Logger.Error(err, "cannot get pods")
return err
}
for _, pod := range podList {
err := h.removeGates(ctx, h.Client, pod, workloadInstance.Namespace)
if err != nil {
h.Logger.Error(err, "cannot remove gates from pod")
return err
}
}
default:
return controllererrors.ErrUnsupportedWorkloadInstanceResourceReference
}

return nil
}

func (h *SchedulingGatesHandler) Enabled() bool {
return h.enabled
}

func removePodGates(ctx context.Context, c client.Client, podName string, podNamespace string) error {
pod := &v1.Pod{}
err := c.Get(ctx, types.NamespacedName{Namespace: podNamespace, Name: podName}, pod)
if err != nil {
return err
}

if pod.Annotations[apicommon.SchedulingGateRemoved] != "" {
return nil
}

if len(pod.Annotations) == 0 {
pod.Annotations = make(map[string]string, 1)
}
pod.Annotations[apicommon.SchedulingGateRemoved] = "true"
pod.Spec.SchedulingGates = nil
return c.Update(ctx, pod)
}

func getPodsOfOwner(ctx context.Context, c client.Client, ownerUID types.UID, ownerKind string, namespace string) ([]string, error) {
pods := &v1.PodList{}
err := c.List(ctx, pods, client.InNamespace(namespace))
if err != nil {
return nil, err
}

var resultPods []string

for _, pod := range pods.Items {
for _, owner := range pod.OwnerReferences {
if owner.Kind == ownerKind && owner.UID == ownerUID {
resultPods = append(resultPods, pod.Name)
break
}
}
}

return resultPods, nil
}
Loading

0 comments on commit b40503e

Please sign in to comment.