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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ go.work.sum
.env

# kubebuilder binaries
# bin/
bin/
6 changes: 6 additions & 0 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
resources:
- manager.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
newName: example.com/operation-cache-controller
newTag: v0.0.1
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ godebug default=go1.23
require (
github.com/onsi/ginkgo/v2 v2.22.0
github.com/onsi/gomega v1.36.1
github.com/stretchr/testify v1.9.0
k8s.io/api v0.32.1
k8s.io/apimachinery v0.32.1
k8s.io/client-go v0.32.1
Expand Down Expand Up @@ -52,6 +53,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
Expand Down
14 changes: 14 additions & 0 deletions internal/utils/controller/appdeployment/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package appdeployment

import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

appv1 "github.com/Azure/operation-cache-controller/api/v1"
)

func ClearConditions(ctx context.Context, appdeployment *appv1.AppDeployment) {
// Clear all conditions
appdeployment.Status.Conditions = []metav1.Condition{}
}
53 changes: 53 additions & 0 deletions internal/utils/controller/appdeployment/conditions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package appdeployment_test

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

appv1 "github.com/Azure/operation-cache-controller/api/v1"
"github.com/Azure/operation-cache-controller/internal/utils/controller/appdeployment"
)

func TestClearConditions(t *testing.T) {
tests := []struct {
name string
existingConditions []metav1.Condition
}{
{
name: "No existing conditions",
existingConditions: []metav1.Condition{},
},
{
name: "Multiple existing conditions",
existingConditions: []metav1.Condition{
{
Type: "TestType",
Status: metav1.ConditionTrue,
Reason: "TestReason",
Message: "TestMessage",
},
{
Type: "AnotherTestType",
Status: metav1.ConditionFalse,
Reason: "AnotherTestReason",
Message: "AnotherTestMessage",
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
appDep := &appv1.AppDeployment{
Status: appv1.AppDeploymentStatus{
Conditions: tt.existingConditions,
},
}
appdeployment.ClearConditions(context.Background(), appDep)
assert.Empty(t, appDep.Status.Conditions, "conditions should be cleared")
})
}
}
17 changes: 17 additions & 0 deletions internal/utils/controller/appdeployment/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package appdeployment

const (
FinalizerName = "finalizer.appdeployment.devinfra.goms.io"

// phase types
PhaseEmpty = ""
PhasePending = "Pending"
PhaseDeploying = "Deploying"
PhaseReady = "Ready"
PhaseDeleting = "Deleting"
PhaseDeleted = "Deleted"

// log keys
LogKeyJobName = "jobName"
LogKeyAppDeploymentName = "appDeploymentName"
)
132 changes: 132 additions & 0 deletions internal/utils/controller/appdeployment/job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package appdeployment

import (
"context"

batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

appv1 "github.com/Azure/operation-cache-controller/api/v1"
)

const (
OperationIDEnvKey = "OPERATION_ID"

JobTypeProvision = "provision"
JobTypeTeardown = "teardown"
)

var (
backOffLimit int32 = 10
ttlSecondsAfterFinished int32 = 3600
MaxAppNameLength int = 36
MaxOpIdLength int = 18
)

func validJName(appName, operationId, jobType string) string {
if len(appName) > MaxAppNameLength {
appName = appName[:MaxAppNameLength]
}
if len(operationId) > MaxOpIdLength {
operationId = operationId[:MaxOpIdLength]
}
originName := jobType + "-" + appName + "-" + operationId
return originName
}

func ProvisionJobFromAppDeploymentSpec(appDeployment *appv1.AppDeployment) *batchv1.Job {
return jobFromAppDeploymentSpec(appDeployment, JobTypeProvision)
}

func TeardownJobFromAppDeploymentSpec(appDeployment *appv1.AppDeployment) *batchv1.Job {
return jobFromAppDeploymentSpec(appDeployment, JobTypeTeardown)
}

func GetProvisionJobName(appDeployment *appv1.AppDeployment) string {
return validJName(appDeployment.Name, appDeployment.Spec.OpId, JobTypeProvision)
}

func GetTeardownJobName(appDeployment *appv1.AppDeployment) string {
return validJName(appDeployment.Name, appDeployment.Spec.OpId, JobTypeTeardown)
}

func jobFromAppDeploymentSpec(appDeployment *appv1.AppDeployment, suffix string) *batchv1.Job {
ops := jobOptions{
name: validJName(appDeployment.Name, appDeployment.Spec.OpId, suffix),
namespace: appDeployment.Namespace,
labels: appDeployment.Labels,
jobSpec: appDeployment.Spec.Provision,
operationID: appDeployment.Spec.OpId,
}
if suffix == JobTypeTeardown {
ops.jobSpec = appDeployment.Spec.Teardown
}
return newJobWithOptions(ops)
}

type jobOptions struct {
name string
namespace string
labels map[string]string
annotations map[string]string
ownerRefs []metav1.OwnerReference
jobSpec batchv1.JobSpec
operationID string
}

func newJobWithOptions(options jobOptions) *batchv1.Job {
options.jobSpec.Template.Spec.Containers[0].Env = append(options.jobSpec.Template.Spec.Containers[0].Env, corev1.EnvVar{
Name: OperationIDEnvKey,
Value: options.operationID,
})
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: options.name,
Namespace: options.namespace,
Labels: options.labels,
Annotations: options.annotations,
},
Spec: options.jobSpec,
}
job.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyOnFailure
job.Spec.BackoffLimit = &backOffLimit
job.Spec.TTLSecondsAfterFinished = &ttlSecondsAfterFinished

if len(options.ownerRefs) > 0 {
job.OwnerReferences = options.ownerRefs
}

return job
}

type JobStatus string

var (
JobStatusSucceeded JobStatus = "Succeeded"
JobStatusFailed JobStatus = "Failed"
JobStatusRunning JobStatus = "Running"
)

func CheckJobStatus(ctx context.Context, job *batchv1.Job) JobStatus {
if job.Status.Succeeded > 0 {
return JobStatusSucceeded
}
if job.Status.Failed > 0 {
return JobStatusFailed
}
return JobStatusRunning
}

func OperationScopedAppDeployment(appName, opId string) string {
if len(appName) > MaxAppNameLength {
appName = appName[:MaxAppNameLength]
}
if len(opId) > MaxOpIdLength {
opId = opId[:MaxOpIdLength]
}
if opId == "" {
return appName
}
return opId + "-" + appName
}
Loading
Loading