internal/utils/controller/operation_helper.go (121 lines of code) (raw):

package controller import ( "sort" "strings" "github.com/google/uuid" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/Azure/operation-cache-controller/api/v1alpha1" ) type OperationHelper struct{} func NewOperationHelper() OperationHelper { return OperationHelper{} } func (ou OperationHelper) IsOperationReady(operation *v1alpha1.Operation) bool { if operation == nil { return false } return operation.Status.Phase == v1alpha1.OperationPhaseReconciled } func (ou OperationHelper) ClearConditions(operation *v1alpha1.Operation) { operation.Status.Conditions = []metav1.Condition{} } // NewOperationId generates a new operation id which is an UUID. func (ou OperationHelper) NewOperationId() string { return strings.Replace(uuid.New().String(), "-", "", -1) } // DiffAppDeployments returns the difference between two slices of AppDeployment. func (ou OperationHelper) DiffAppDeployments(expected, actual []v1alpha1.AppDeployment, equals func(a, b v1alpha1.AppDeployment) bool) (added, removed, updated []v1alpha1.AppDeployment) { // Find added and updated AppDeployments. for _, e := range expected { found := false for _, a := range actual { if a.Name == e.Name { found = true if !equals(a, e) { updated = append(updated, a) } break } } if !found { added = append(added, e) } } // Find removed AppDeployments. for _, a := range actual { found := false for _, e := range expected { if a.Name == e.Name { found = true break } } if !found { removed = append(removed, a) } } return added, removed, updated } func (ou OperationHelper) isJobResultIdentical(a, b batchv1.JobSpec) bool { if len(a.Template.Spec.Containers) == 0 && len(b.Template.Spec.Containers) == 0 { return true } if len(a.Template.Spec.Containers) == 0 || len(b.Template.Spec.Containers) == 0 { return false } if a.Template.Spec.Containers[0].Image != b.Template.Spec.Containers[0].Image { return false } if !isStringSliceIdentical(a.Template.Spec.Containers[0].Command, b.Template.Spec.Containers[0].Command) { return false } if !isStringSliceIdentical(a.Template.Spec.Containers[0].Args, b.Template.Spec.Containers[0].Args) { return false } if a.Template.Spec.Containers[0].WorkingDir != b.Template.Spec.Containers[0].WorkingDir { return false } if !ou.isEnvVarsIdentical(a.Template.Spec.Containers[0].Env, b.Template.Spec.Containers[0].Env) { return false } return true } func (ou OperationHelper) isEnvVarsIdentical(a, b []corev1.EnvVar) bool { if len(a) != len(b) { return false } // sort environment variables to ensure consistent hashing sort.Slice(a, func(i, j int) bool { return a[i].Name < a[j].Name }) sort.Slice(b, func(i, j int) bool { return b[i].Name < b[j].Name }) for i, env := range a { if env.Name != b[i].Name || env.Value != b[i].Value { return false } } return true } func isStringSliceIdentical(a, b []string) bool { if len(a) != len(b) { return false } sort.Strings(a) sort.Strings(b) for i, dep := range a { if dep != b[i] { return false } } return true } func (ou OperationHelper) CompareProvisionJobs(a, b v1alpha1.AppDeployment) bool { if sameProvisionJob := ou.isJobResultIdentical(a.Spec.Provision, b.Spec.Provision); !sameProvisionJob { return false } // Check if the dependencies are the same using the helper function return isStringSliceIdentical(a.Spec.Dependencies, b.Spec.Dependencies) } func (ou OperationHelper) CompareTeardownJobs(a, b v1alpha1.AppDeployment) bool { if sameTeardownJob := ou.isJobResultIdentical(a.Spec.Teardown, b.Spec.Teardown); !sameTeardownJob { return false } return true }