Skip to content

Commit

Permalink
Merge pull request #1226 from equinor/master
Browse files Browse the repository at this point in the history
Release Specify Env for pipeline job, new RadixDeployment CRD, Ingress 503 annotation. Restart Batchjob fix
  • Loading branch information
Richard87 authored Nov 25, 2024
2 parents b8e6f8d + 8e16e50 commit e8ff403
Show file tree
Hide file tree
Showing 25 changed files with 2,143 additions and 205 deletions.
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ deploy-pipeline:
az acr login --name $(CONTAINER_REPO)
docker buildx build -t $(DOCKER_REGISTRY)/radix-pipeline:$(VERSION) -t $(DOCKER_REGISTRY)/radix-pipeline:$(BRANCH)-$(VERSION) -t $(DOCKER_REGISTRY)/radix-pipeline:$(TAG) --platform linux/arm64,linux/amd64 -f pipeline.Dockerfile --push .

.PHONY: deploy-pipeline-arm64
deploy-pipeline-arm64:
az acr login --name $(CONTAINER_REPO)
docker buildx build -t $(DOCKER_REGISTRY)/radix-pipeline:$(VERSION) -t $(DOCKER_REGISTRY)/radix-pipeline:$(BRANCH)-$(VERSION) -t $(DOCKER_REGISTRY)/radix-pipeline:$(TAG) --platform linux/arm64 -f pipeline.Dockerfile --push .

.PHONY: build-operator
build-operator:
docker build -t $(DOCKER_REGISTRY)/radix-operator:$(VERSION) -t $(DOCKER_REGISTRY)/radix-operator:$(BRANCH)-$(VERSION) -t $(DOCKER_REGISTRY)/radix-operator:$(TAG) -f operator.Dockerfile .
Expand All @@ -127,7 +132,7 @@ code-gen: bootstrap
./hack/update-codegen.sh

.PHONY: crds
crds: temp-crds radixapplication-crd radixbatch-crd radixdnsalias-crd delete-temp-crds
crds: temp-crds radixapplication-crd radixbatch-crd radixdnsalias-crd radixdeployment-crd delete-temp-crds

.PHONY: radixapplication-crd
radixapplication-crd: temp-crds
Expand All @@ -138,6 +143,10 @@ radixapplication-crd: temp-crds
radixbatch-crd: temp-crds
cp $(CRD_TEMP_DIR)radix.equinor.com_radixbatches.yaml $(CRD_CHART_DIR)radixbatch.yaml

.PHONY: radixdeployment-crd
radixdeployment-crd: temp-crds
cp $(CRD_TEMP_DIR)radix.equinor.com_radixdeployments.yaml $(CRD_CHART_DIR)radixdeployment.yaml

.PHONY: radixdnsalias-crd
radixdnsalias-crd: temp-crds
cp $(CRD_TEMP_DIR)radix.equinor.com_radixdnsaliases.yaml $(CRD_CHART_DIR)radixdnsalias.yaml
Expand Down
4 changes: 2 additions & 2 deletions charts/radix-operator/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: radix-operator
version: 1.45.1
appVersion: 1.65.1
version: 1.46.3
appVersion: 1.66.3
kubeVersion: ">=1.24.0"
description: Radix Operator
keywords:
Expand Down
1,590 changes: 1,578 additions & 12 deletions charts/radix-operator/templates/radixdeployment.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pipeline-runner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func setPipelineArgsFromArguments(cmd *cobra.Command, pipelineArgs *model.Pipeli
cmd.Flags().StringVar(&pipelineArgs.CommitID, defaults.RadixCommitIdEnvironmentVariable, "", "Commit ID to build from")
cmd.Flags().StringVar(&pipelineArgs.DeploymentName, defaults.RadixPromoteDeploymentEnvironmentVariable, "", "Radix deployment name")
cmd.Flags().StringVar(&pipelineArgs.FromEnvironment, defaults.RadixPromoteFromEnvironmentEnvironmentVariable, "", "Radix application environment name to promote from")
cmd.Flags().StringVar(&pipelineArgs.ToEnvironment, defaults.RadixPromoteToEnvironmentEnvironmentVariable, "", "Radix application environment name to promote to")
cmd.Flags().StringVar(&pipelineArgs.ToEnvironment, defaults.RadixPipelineJobToEnvironmentEnvironmentVariable, "", "Radix application environment name to build-deploy or promote to")
cmd.Flags().StringVar(&pipelineArgs.TektonPipeline, defaults.RadixTektonPipelineImageEnvironmentVariable, "", "Radix Tekton docker image")
cmd.Flags().StringVar(&pipelineArgs.ImageBuilder, defaults.RadixImageBuilderEnvironmentVariable, "", "Radix Image Builder docker image")
cmd.Flags().StringVar(&pipelineArgs.BuildKitImageBuilder, defaults.RadixBuildKitImageBuilderEnvironmentVariable, "", "Radix Build Kit Image Builder container image")
Expand Down
6 changes: 6 additions & 0 deletions pipeline-runner/model/pipelineInfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ func (info *PipelineInfo) SetApplicationConfig(applicationConfig *application.Ap
targetEnvironments = append(targetEnvironments, info.PipelineArguments.ToEnvironment)
}

// For build and build-deploy pipeline
if (info.IsPipelineType(radixv1.Build) || info.IsPipelineType(radixv1.BuildDeploy)) &&
len(info.PipelineArguments.ToEnvironment) > 0 {
targetEnvironments = []string{info.PipelineArguments.ToEnvironment}
}

info.TargetEnvironments = targetEnvironments
}

Expand Down
2 changes: 1 addition & 1 deletion pipeline-runner/steps/preparepipeline/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func (cli *PreparePipelinesStepImplementation) getPreparePipelinesJobConfig(pipe
Value: pipelineInfo.PipelineArguments.FromEnvironment,
},
{
Name: defaults.RadixPromoteToEnvironmentEnvironmentVariable,
Name: defaults.RadixPipelineJobToEnvironmentEnvironmentVariable,
Value: pipelineInfo.PipelineArguments.ToEnvironment,
},
{
Expand Down
2 changes: 1 addition & 1 deletion pipeline-runner/steps/runpipeline/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (step *RunPipelinesStepImplementation) getRunTektonPipelinesJobConfig(pipel
Value: pipelineInfo.PipelineArguments.FromEnvironment,
},
{
Name: defaults.RadixPromoteToEnvironmentEnvironmentVariable,
Name: defaults.RadixPipelineJobToEnvironmentEnvironmentVariable,
Value: pipelineInfo.PipelineArguments.ToEnvironment,
},
{
Expand Down
63 changes: 15 additions & 48 deletions pkg/apis/batch/kubejob.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,34 @@ const (
)

func (s *syncer) reconcileKubeJob(ctx context.Context, batchJob *radixv1.RadixBatchJob, rd *radixv1.RadixDeployment, jobComponent *radixv1.RadixDeployJobComponent, existingJobs []*batchv1.Job) error {
batchJobKubeJobs := slice.FindAll(existingJobs, isKubeJobForBatchJob(batchJob))

if isBatchJobStopRequested(batchJob) {
// Delete existing k8s job if stop is requested for batch job
batchJobKubeJobs := slice.FindAll(existingJobs, func(job *batchv1.Job) bool { return isResourceLabeledWithBatchJobName(batchJob.Name, job) })
return s.deleteJobs(ctx, batchJobKubeJobs)
}

jobNeedToBeRestarted, err := s.handleJobToRestart(ctx, batchJob, existingJobs)
if err != nil {
return err
}
if !jobNeedToBeRestarted && (isBatchJobDone(s.radixBatch, batchJob.Name) ||
slice.Any(existingJobs, func(job *batchv1.Job) bool { return isResourceLabeledWithBatchJobName(batchJob.Name, job) })) {
requiresRestart := s.jobRequiresRestart(*batchJob)
if !requiresRestart && (s.isBatchJobDone(batchJob.Name) || len(batchJobKubeJobs) > 0) {
return nil
}
err = s.validatePayloadSecretReference(ctx, batchJob, jobComponent)
if err != nil {

if requiresRestart {
s.restartedJobs[batchJob.Name] = *batchJob
if err := s.deleteJobs(ctx, batchJobKubeJobs); err != nil {
return err
}
}

if err := s.validatePayloadSecretReference(ctx, batchJob, jobComponent); err != nil {
return err
}

job, err := s.buildJob(ctx, batchJob, jobComponent, rd)
if err != nil {
return err
}

return retry.RetryOnConflict(retry.DefaultRetry, func() error {
_, err = s.kubeClient.BatchV1().Jobs(s.radixBatch.GetNamespace()).Create(ctx, job, metav1.CreateOptions{})
return err
Expand All @@ -76,45 +82,6 @@ func (s *syncer) validatePayloadSecretReference(ctx context.Context, batchJob *r
return nil
}

func (s *syncer) handleJobToRestart(ctx context.Context, batchJob *radixv1.RadixBatchJob, existingJobs []*batchv1.Job) (bool, error) {
jobStatusIdx := slice.FindIndex(s.radixBatch.Status.JobStatuses, func(jobStatus radixv1.RadixBatchJobStatus) bool {
return jobStatus.Name == batchJob.Name
})

jobRestartTimestamp, jobStatusRestartTimestamp := s.getJobRestartTimestamps(batchJob, jobStatusIdx)
if !needRestartJob(jobRestartTimestamp, jobStatusRestartTimestamp) {
return false, nil
}

jobsToDelete := slice.FindAll(existingJobs, func(job *batchv1.Job) bool { return isResourceLabeledWithBatchJobName(batchJob.Name, job) })
err := s.deleteJobs(ctx, jobsToDelete)
if err != nil {
return true, err
}

jobStatus := radixv1.RadixBatchJobStatus{
Name: batchJob.Name,
Restart: jobRestartTimestamp,
}
if jobStatusIdx >= 0 {
s.radixBatch.Status.JobStatuses[jobStatusIdx] = jobStatus
return true, nil
}
s.radixBatch.Status.JobStatuses = append(s.radixBatch.Status.JobStatuses, jobStatus)
return true, nil
}

func needRestartJob(jobRestartTimestamp string, jobStatusRestartTimestamp string) bool {
return len(jobRestartTimestamp) > 0 && jobRestartTimestamp != jobStatusRestartTimestamp
}

func (s *syncer) getJobRestartTimestamps(batchJob *radixv1.RadixBatchJob, jobStatusIdx int) (string, string) {
if jobStatusIdx >= 0 {
return batchJob.Restart, s.radixBatch.Status.JobStatuses[jobStatusIdx].Restart
}
return batchJob.Restart, ""
}

func (s *syncer) deleteJobs(ctx context.Context, jobsToDelete []*batchv1.Job) error {
for _, jobToDelete := range jobsToDelete {
err := s.kubeClient.BatchV1().Jobs(jobToDelete.GetNamespace()).Delete(ctx, jobToDelete.GetName(), metav1.DeleteOptions{PropagationPolicy: pointers.Ptr(metav1.DeletePropagationBackground)})
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/batch/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (s *syncer) reconcileService(ctx context.Context, batchJob *radixv1.RadixBa
return nil
}

if isBatchJobStopRequested(batchJob) || isBatchJobDone(s.radixBatch, batchJob.Name) {
if isBatchJobStopRequested(batchJob) || s.isBatchJobDone(batchJob.Name) {
return nil
}

Expand Down
16 changes: 12 additions & 4 deletions pkg/apis/batch/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,28 @@ func (s *syncer) buildJobStatuses(ctx context.Context) ([]radixv1.RadixBatchJobS
}

func (s *syncer) buildBatchJobStatus(ctx context.Context, batchJob *radixv1.RadixBatchJob, allJobs []*batchv1.Job) radixv1.RadixBatchJobStatus {
restartedJob, isRestartedJob := s.restartedJobs[batchJob.Name]

currentStatus, hasCurrentStatus := slice.FindFirst(s.radixBatch.Status.JobStatuses, func(jobStatus radixv1.RadixBatchJobStatus) bool {
return jobStatus.Name == batchJob.Name
})
if hasCurrentStatus && isJobStatusDone(currentStatus) {

if !isRestartedJob && hasCurrentStatus && isJobStatusDone(currentStatus) {
return currentStatus
}

status := radixv1.RadixBatchJobStatus{
Name: batchJob.Name,
Phase: radixv1.BatchJobPhaseWaiting,
}
if hasCurrentStatus {
status.Restart = currentStatus.Restart

if isRestartedJob {
status.Restart = restartedJob.Restart
}

if hasCurrentStatus && !isRestartedJob {
status.Phase = currentStatus.Phase
status.Restart = currentStatus.Restart
}

if isBatchJobStopRequested(batchJob) {
Expand All @@ -151,7 +159,7 @@ func (s *syncer) buildBatchJobStatus(ctx context.Context, batchJob *radixv1.Radi
return status
}

job, jobFound := slice.FindFirst(allJobs, func(job *batchv1.Job) bool { return isResourceLabeledWithBatchJobName(batchJob.Name, job) })
job, jobFound := slice.FindFirst(allJobs, isKubeJobForBatchJob(batchJob))
if !jobFound {
return status
}
Expand Down
60 changes: 46 additions & 14 deletions pkg/apis/batch/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/equinor/radix-common/utils/slice"
"github.com/equinor/radix-operator/pkg/apis/config"
"github.com/equinor/radix-operator/pkg/apis/kube"
radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
Expand All @@ -15,6 +16,10 @@ import (
"k8s.io/client-go/kubernetes"
)

const (
syncStatusForEveryNumberOfBatchJobsReconciled = 10
)

// Syncer of RadixBatch
type Syncer interface {
// OnSync Syncs RadixBatch
Expand All @@ -24,20 +29,22 @@ type Syncer interface {
// NewSyncer Constructor os RadixBatches Syncer
func NewSyncer(kubeclient kubernetes.Interface, kubeUtil *kube.Kube, radixClient radixclient.Interface, radixBatch *radixv1.RadixBatch, config *config.Config) Syncer {
return &syncer{
kubeClient: kubeclient,
kubeUtil: kubeUtil,
radixClient: radixClient,
radixBatch: radixBatch,
config: config,
kubeClient: kubeclient,
kubeUtil: kubeUtil,
radixClient: radixClient,
radixBatch: radixBatch,
config: config,
restartedJobs: map[string]radixv1.RadixBatchJob{},
}
}

type syncer struct {
kubeClient kubernetes.Interface
kubeUtil *kube.Kube
radixClient radixclient.Interface
radixBatch *radixv1.RadixBatch
config *config.Config
kubeClient kubernetes.Interface
kubeUtil *kube.Kube
radixClient radixclient.Interface
radixBatch *radixv1.RadixBatch
config *config.Config
restartedJobs map[string]radixv1.RadixBatchJob
}

// OnSync Syncs RadixBatches
Expand All @@ -49,16 +56,14 @@ func (s *syncer) OnSync(ctx context.Context) error {
return err
}

if isBatchDone(s.radixBatch) {
if s.isBatchDone() && !s.isRestartRequestedForAnyBatchJob() {
return nil
}

return s.syncStatus(ctx, s.reconcile(ctx))
}

func (s *syncer) reconcile(ctx context.Context) error {
const syncStatusForEveryNumberOfBatchJobsReconciled = 10

rd, jobComponent, err := s.getRadixDeploymentAndJobComponent(ctx)
if err != nil {
return err
Expand All @@ -83,7 +88,7 @@ func (s *syncer) reconcile(ctx context.Context) error {
return fmt.Errorf("batchjob %s: failed to reconcile kubejob: %w", batchJob.Name, err)
}

if i%syncStatusForEveryNumberOfBatchJobsReconciled == 0 {
if i%syncStatusForEveryNumberOfBatchJobsReconciled == (syncStatusForEveryNumberOfBatchJobsReconciled - 1) {
if err := s.syncStatus(ctx, nil); err != nil {
return fmt.Errorf("batchjob %s: failed to sync status: %w", batchJob.Name, err)
}
Expand Down Expand Up @@ -129,3 +134,30 @@ func (s *syncer) batchJobIdentifierLabel(batchJobName, appName string) labels.Se
radixlabels.ForBatchJobName(batchJobName),
)
}

func (s *syncer) jobRequiresRestart(job radixv1.RadixBatchJob) bool {
if job.Restart == "" {
return false
}

currentStatus, found := slice.FindFirst(s.radixBatch.Status.JobStatuses, func(jobStatus radixv1.RadixBatchJobStatus) bool {
return jobStatus.Name == job.Name
})

return !found || job.Restart != currentStatus.Restart
}

func (s *syncer) isBatchDone() bool {
return s.radixBatch.Status.Condition.Type == radixv1.BatchConditionTypeCompleted
}

func (s *syncer) isBatchJobDone(batchJobName string) bool {
return slice.Any(s.radixBatch.Status.JobStatuses,
func(jobStatus radixv1.RadixBatchJobStatus) bool {
return jobStatus.Name == batchJobName && isJobStatusDone(jobStatus)
})
}

func (s *syncer) isRestartRequestedForAnyBatchJob() bool {
return slice.Any(s.radixBatch.Spec.Jobs, s.jobRequiresRestart)
}
Loading

0 comments on commit e8ff403

Please sign in to comment.