Skip to content

Commit

Permalink
Merge pull request #194 from uselagoon/queued-status
Browse files Browse the repository at this point in the history
  • Loading branch information
shreddedbacon authored Dec 5, 2022
2 parents 5b9a4ac + eb8b734 commit 418ea00
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 88 deletions.
14 changes: 13 additions & 1 deletion apis/lagoon/v1beta1/lagoonbuild_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.
package v1beta1

import (
"strings"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand All @@ -25,8 +27,10 @@ type BuildStatusType string

// These are valid conditions of a job.
const (
// BuildStatusRunning means the build is pending.
// BuildStatusPending means the build is pending.
BuildStatusPending BuildStatusType = "Pending"
// BuildStatusQueued means the build is queued.
BuildStatusQueued BuildStatusType = "Queued"
// BuildStatusRunning means the build is running.
BuildStatusRunning BuildStatusType = "Running"
// BuildStatusComplete means the build has completed its execution.
Expand All @@ -37,6 +41,14 @@ const (
BuildStatusCancelled BuildStatusType = "Cancelled"
)

func (b BuildStatusType) String() string {
return string(b)
}

func (b BuildStatusType) ToLower() string {
return strings.ToLower(b.String())
}

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

Expand Down
26 changes: 21 additions & 5 deletions apis/lagoon/v1beta1/lagoontask_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.
package v1beta1

import (
"strings"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand All @@ -28,29 +30,43 @@ type TaskStatusType string

// These are valid conditions of a job.
const (
// TaskStatusRunning means the build is pending.
// TaskStatusPending means the job is pending.
TaskStatusPending TaskStatusType = "Pending"
// TaskStatusRunning means the build is running.
// TaskStatusQueued means the job is queued.
TaskStatusQueued TaskStatusType = "Queued"
// TaskStatusRunning means the job is running.
TaskStatusRunning TaskStatusType = "Running"
// TaskStatusComplete means the build has completed its execution.
// TaskStatusComplete means the job has completed its execution.
TaskStatusComplete TaskStatusType = "Complete"
// TaskStatusFailed means the job has failed its execution.
TaskStatusFailed TaskStatusType = "Failed"
// TaskStatusCancelled means the job been cancelled.
TaskStatusCancelled TaskStatusType = "Cancelled"
)

func (b TaskStatusType) String() string {
return string(b)
}

func (b TaskStatusType) ToLower() string {
return strings.ToLower(b.String())
}

// TaskType const for the status type
type TaskType string

// These are valid conditions of a job.
const (
// TaskStatusRunning means the build is pending.
// TaskTypeStandard means the task is a standard task.
TaskTypeStandard TaskType = "standard"
// TaskStatusRunning means the build is running.
// TaskTypeAdvanced means the task is an advanced task.
TaskTypeAdvanced TaskType = "advanced"
)

func (b TaskType) String() string {
return string(b)
}

// LagoonTaskSpec defines the desired state of LagoonTask
type LagoonTaskSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
Expand Down
8 changes: 4 additions & 4 deletions controllers/v1beta1/build_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (r *LagoonBuildReconciler) Reconcile(ctx context.Context, req ctrl.Request)
// if the build isn't being deleted, but the status is cancelled
// then clean up the undeployable build
if value, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; ok {
if value == string(lagoonv1beta1.BuildStatusCancelled) {
if value == lagoonv1beta1.BuildStatusCancelled.String() {
if value, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/cancelledByNewBuild"]; ok {
if value == "true" {
opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled by new build", lagoonBuild.ObjectMeta.Name))
Expand All @@ -142,7 +142,7 @@ func (r *LagoonBuildReconciler) Reconcile(ctx context.Context, req ctrl.Request)
listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{
client.InNamespace(req.Namespace),
client.MatchingLabels(map[string]string{
"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusRunning),
"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusRunning.String(),
"lagoon.sh/controller": r.ControllerNamespace,
}),
})
Expand Down Expand Up @@ -261,7 +261,7 @@ func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context,
// the `lagoon.sh/buildStatus = Pending` now
// so end this reconcile process
pendingBuilds := &lagoonv1beta1.LagoonBuildList{}
return ctrl.Result{}, helpers.CancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, namespace.ObjectMeta.Name, string(lagoonv1beta1.BuildStatusPending))
return ctrl.Result{}, helpers.CancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, namespace.ObjectMeta.Name, lagoonv1beta1.BuildStatusPending.String())
}

// getOrCreateBuildResource will deepcopy the lagoon build into a new resource and push it to the new namespace
Expand All @@ -272,7 +272,7 @@ func (r *LagoonBuildReconciler) getOrCreateBuildResource(ctx context.Context, bu
newBuild.SetResourceVersion("")
newBuild.SetLabels(
map[string]string{
"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusPending),
"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusPending.String(),
"lagoon.sh/controller": r.ControllerNamespace,
},
)
Expand Down
62 changes: 32 additions & 30 deletions controllers/v1beta1/build_deletionhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources(
listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{
client.InNamespace(lagoonBuild.ObjectMeta.Namespace),
client.MatchingLabels(map[string]string{
"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusRunning),
"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusRunning.String(),
"lagoon.sh/controller": r.ControllerNamespace,
}),
})
Expand All @@ -111,7 +111,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources(
listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{
client.InNamespace(lagoonBuild.ObjectMeta.Namespace),
client.MatchingLabels(map[string]string{
"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusPending),
"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusPending.String(),
"lagoon.sh/controller": r.ControllerNamespace,
}),
})
Expand All @@ -138,7 +138,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources(
mergePatch, _ := json.Marshal(map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusRunning),
"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusRunning.String(),
},
},
})
Expand Down Expand Up @@ -185,11 +185,11 @@ Build cancelled
========================================`))
var buildCondition lagoonv1beta1.BuildStatusType
buildCondition = lagoonv1beta1.BuildStatusCancelled
lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(buildCondition)
lagoonBuild.Labels["lagoon.sh/buildStatus"] = buildCondition.String()
mergePatch, _ := json.Marshal(map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"lagoon.sh/buildStatus": string(buildCondition),
"lagoon.sh/buildStatus": buildCondition.String(),
},
},
})
Expand All @@ -212,33 +212,37 @@ Build cancelled
}
}
// send any messages to lagoon message queues
// update the deployment with the status
r.cancelledBuildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv)
r.updateCancelledDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv)
r.cancelledBuildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs)
// update the deployment with the status of cancelled in lagoon
r.buildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusCancelled)
r.updateDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusCancelled)
r.buildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs, lagoonv1beta1.BuildStatusCancelled)
}
return nil
}

// cancelledBuildLogsToLagoonLogs sends the build logs to the lagoon-logs message queue
// buildLogsToLagoonLogs sends the build logs to the lagoon-logs message queue
// it contains the actual pod log output that is sent to elasticsearch, it is what eventually is displayed in the UI
func (r *LagoonBuildReconciler) cancelledBuildLogsToLagoonLogs(ctx context.Context,
func (r *LagoonBuildReconciler) buildLogsToLagoonLogs(ctx context.Context,
opLog logr.Logger,
lagoonBuild *lagoonv1beta1.LagoonBuild,
logs []byte,
buildCondition lagoonv1beta1.BuildStatusType,
) {
if r.EnableMQ {
condition := "cancelled"
buildStep := "cancelled"
condition := buildCondition
buildStep := "queued"
if condition == lagoonv1beta1.BuildStatusCancelled {
buildStep = "cancelled"
}
msg := lagoonv1beta1.LagoonLog{
Severity: "info",
Project: lagoonBuild.Spec.Project.Name,
Event: "build-logs:builddeploy-kubernetes:" + lagoonBuild.ObjectMeta.Name,
Meta: &lagoonv1beta1.LagoonLogMeta{
JobName: lagoonBuild.ObjectMeta.Name, // @TODO: remove once lagoon is corrected in controller-handler
BuildName: lagoonBuild.ObjectMeta.Name,
BuildPhase: condition, // @TODO: same as buildstatus label, remove once lagoon is corrected in controller-handler
BuildStatus: condition, // same as buildstatus label
BuildPhase: buildCondition.ToLower(), // @TODO: same as buildstatus label, remove once lagoon is corrected in controller-handler
BuildStatus: buildCondition.ToLower(), // same as buildstatus label
BuildStep: buildStep,
BranchName: lagoonBuild.Spec.Project.Environment,
RemoteID: string(lagoonBuild.ObjectMeta.UID),
Expand All @@ -247,10 +251,7 @@ func (r *LagoonBuildReconciler) cancelledBuildLogsToLagoonLogs(ctx context.Conte
},
}
// add the actual build log message
msg.Message = fmt.Sprintf(`========================================
Logs on pod %s
========================================
%s`, lagoonBuild.ObjectMeta.Name, logs)
msg.Message = fmt.Sprintf("%s", logs)
msgBytes, err := json.Marshal(msg)
if err != nil {
opLog.Error(err, "Unable to encode message as JSON")
Expand All @@ -271,12 +272,13 @@ Logs on pod %s
}
}

// updateCancelledDeploymentAndEnvironmentTask sends the status of the build and deployment to the controllerhandler message queue in lagoon,
// updateDeploymentAndEnvironmentTask sends the status of the build and deployment to the controllerhandler message queue in lagoon,
// this is for the handler in lagoon to process.
func (r *LagoonBuildReconciler) updateCancelledDeploymentAndEnvironmentTask(ctx context.Context,
func (r *LagoonBuildReconciler) updateDeploymentAndEnvironmentTask(ctx context.Context,
opLog logr.Logger,
lagoonBuild *lagoonv1beta1.LagoonBuild,
lagoonEnv *corev1.ConfigMap,
buildCondition lagoonv1beta1.BuildStatusType,
) {
namespace := helpers.GenerateNamespaceName(
lagoonBuild.Spec.Project.NamespacePattern, // the namespace pattern or `openshiftProjectPattern` from Lagoon is never received by the controller
Expand All @@ -287,14 +289,13 @@ func (r *LagoonBuildReconciler) updateCancelledDeploymentAndEnvironmentTask(ctx
r.RandomNamespacePrefix,
)
if r.EnableMQ {
condition := "cancelled"
msg := lagoonv1beta1.LagoonMessage{
Type: "build",
Namespace: namespace,
Meta: &lagoonv1beta1.LagoonLogMeta{
Environment: lagoonBuild.Spec.Project.Environment,
Project: lagoonBuild.Spec.Project.Name,
BuildPhase: condition,
BuildPhase: buildCondition.ToLower(),
BuildName: lagoonBuild.ObjectMeta.Name,
LogLink: lagoonBuild.Spec.Project.UILink,
RemoteID: string(lagoonBuild.ObjectMeta.UID),
Expand Down Expand Up @@ -363,21 +364,22 @@ func (r *LagoonBuildReconciler) updateCancelledDeploymentAndEnvironmentTask(ctx
}
}

// cancelledBuildStatusLogsToLagoonLogs sends the logs to lagoon-logs message queue, used for general messaging
func (r *LagoonBuildReconciler) cancelledBuildStatusLogsToLagoonLogs(ctx context.Context,
// buildStatusLogsToLagoonLogs sends the logs to lagoon-logs message queue, used for general messaging
func (r *LagoonBuildReconciler) buildStatusLogsToLagoonLogs(ctx context.Context,
opLog logr.Logger,
lagoonBuild *lagoonv1beta1.LagoonBuild,
lagoonEnv *corev1.ConfigMap) {
lagoonEnv *corev1.ConfigMap,
buildCondition lagoonv1beta1.BuildStatusType,
) {
if r.EnableMQ {
condition := "cancelled"
msg := lagoonv1beta1.LagoonLog{
Severity: "info",
Project: lagoonBuild.Spec.Project.Name,
Event: "task:builddeploy-kubernetes:" + condition, //@TODO: this probably needs to be changed to a new task event for the controller
Event: "task:builddeploy-kubernetes:" + buildCondition.ToLower(), //@TODO: this probably needs to be changed to a new task event for the controller
Meta: &lagoonv1beta1.LagoonLogMeta{
ProjectName: lagoonBuild.Spec.Project.Name,
BranchName: lagoonBuild.Spec.Project.Environment,
BuildPhase: condition,
BuildPhase: buildCondition.ToLower(),
BuildName: lagoonBuild.ObjectMeta.Name,
LogLink: lagoonBuild.Spec.Project.UILink,
Cluster: r.LagoonTargetName,
Expand All @@ -386,7 +388,7 @@ func (r *LagoonBuildReconciler) cancelledBuildStatusLogsToLagoonLogs(ctx context
lagoonBuild.Spec.Project.Name,
lagoonBuild.Spec.Project.Environment,
lagoonBuild.ObjectMeta.Name,
"cancelled",
buildCondition.ToLower(),
),
}
// if we aren't being provided the lagoon config, we can skip adding the routes etc
Expand Down
57 changes: 48 additions & 9 deletions controllers/v1beta1/build_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,46 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log
return nil
}

// cleanUpUndeployableBuild will clean up a build if the namespace is being terminated, or some other reason that it can't deploy (or create the pod)
// updateQueuedBuild will update a build if it is queued
func (r *LagoonBuildReconciler) updateQueuedBuild(
ctx context.Context,
lagoonBuild lagoonv1beta1.LagoonBuild,
message string,
opLog logr.Logger,
) error {
var allContainerLogs []byte
// if we get this handler, then it is likely that the build was in a pending or running state with no actual running pod
// so just set the logs to be cancellation message
allContainerLogs = []byte(fmt.Sprintf(`
========================================
%s
========================================
`, message))
// get the configmap for lagoon-env so we can use it for updating the deployment in lagoon
var lagoonEnv corev1.ConfigMap
err := r.Get(ctx, types.NamespacedName{
Namespace: lagoonBuild.ObjectMeta.Namespace,
Name: "lagoon-env",
},
&lagoonEnv,
)
if err != nil {
// if there isn't a configmap, just info it and move on
// the updatedeployment function will see it as nil and not bother doing the bits that require the configmap
if r.EnableDebug {
opLog.Info(fmt.Sprintf("There is no configmap %s in namespace %s ", "lagoon-env", lagoonBuild.ObjectMeta.Namespace))
}
}
// send any messages to lagoon message queues
// update the deployment with the status
//@TODO: change BuildStatusPending to BuildStatusQueued when lagoon supports queued
r.buildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusPending)
r.updateDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusPending)
r.buildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs, lagoonv1beta1.BuildStatusPending)
return nil
}

// cleanUpUndeployableBuild will clean up a build if the namespace is being terminated, or some other reason that it can't deploy (or create the pod, pending in queue)
func (r *LagoonBuildReconciler) cleanUpUndeployableBuild(
ctx context.Context,
lagoonBuild lagoonv1beta1.LagoonBuild,
Expand All @@ -960,11 +999,11 @@ Build cancelled
%s`, message))
var buildCondition lagoonv1beta1.BuildStatusType
buildCondition = lagoonv1beta1.BuildStatusCancelled
lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(buildCondition)
lagoonBuild.Labels["lagoon.sh/buildStatus"] = buildCondition.String()
mergePatch, _ := json.Marshal(map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"lagoon.sh/buildStatus": string(buildCondition),
"lagoon.sh/buildStatus": buildCondition.String(),
},
},
})
Expand All @@ -988,11 +1027,11 @@ Build cancelled
}
}
// send any messages to lagoon message queues
// update the deployment with the status
r.cancelledBuildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv)
r.updateCancelledDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv)
// update the deployment with the status of cancelled in lagoon
r.buildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusCancelled)
r.updateDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv, lagoonv1beta1.BuildStatusCancelled)
if cancelled {
r.cancelledBuildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs)
r.buildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs, lagoonv1beta1.BuildStatusCancelled)
}
// delete the build from the lagoon namespace in kubernetes entirely
err = r.Delete(ctx, &lagoonBuild)
Expand All @@ -1005,7 +1044,7 @@ Build cancelled
func (r *LagoonBuildReconciler) cancelExtraBuilds(ctx context.Context, opLog logr.Logger, pendingBuilds *lagoonv1beta1.LagoonBuildList, ns string, status string) error {
listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{
client.InNamespace(ns),
client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": string(lagoonv1beta1.BuildStatusPending)}),
client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": lagoonv1beta1.BuildStatusPending.String()}),
})
if err := r.List(ctx, pendingBuilds, listOption); err != nil {
return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err)
Expand All @@ -1026,7 +1065,7 @@ func (r *LagoonBuildReconciler) cancelExtraBuilds(ctx context.Context, opLog log
} else {
// cancel any other pending builds
opLog.Info(fmt.Sprintf("Attempting to cancel build %s", pendingBuild.ObjectMeta.Name))
pendingBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1beta1.BuildStatusCancelled)
pendingBuild.Labels["lagoon.sh/buildStatus"] = lagoonv1beta1.BuildStatusCancelled.String()
}
if err := r.Update(ctx, pendingBuild); err != nil {
return fmt.Errorf("There was an error updating the pending build. Error was: %v", err)
Expand Down
Loading

0 comments on commit 418ea00

Please sign in to comment.