Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: (cluster) Promotion tasks #3121

Merged
merged 38 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
01b118d
feat(api): add `PromotionTask` kind
hiddeco Dec 10, 2024
c4ec253
chore: run codegen
hiddeco Dec 10, 2024
a2b05ca
feat(api): add `ClusterPromotionTask`
hiddeco Dec 10, 2024
8bf98a8
chore: run codegen
hiddeco Dec 10, 2024
bd6ffab
feat(api): add `Task` field to `PromotionStep`
hiddeco Dec 10, 2024
18cf89f
chore: run codegen
hiddeco Dec 10, 2024
2845b7f
feat(api): add validation rules for Promotion steps
hiddeco Dec 11, 2024
35b2552
chore: run codegen
hiddeco Dec 11, 2024
2563b9f
feat(api): allow `Inputs` config on `PromotionStep`
hiddeco Dec 11, 2024
e34147d
chore: run codegen
hiddeco Dec 11, 2024
bf087e5
fix(api): register new kinds
hiddeco Dec 12, 2024
722a6a6
feat(kargo): introduce `PromotionBuilder`
hiddeco Dec 11, 2024
023465f
chore: fix broken tests
hiddeco Dec 12, 2024
a3702c7
fix(api): make PromotionStep input field a list
hiddeco Dec 13, 2024
65cf54d
chore: run codegen
hiddeco Dec 13, 2024
1510b7b
chore(directives): wire inputs into engine
hiddeco Dec 13, 2024
72d06cb
feat(directives): add `compose-output` directive
hiddeco Dec 13, 2024
87631dd
chore(api): `Inputs` -> `Vars`
hiddeco Dec 16, 2024
478ca82
chore: run codegen
hiddeco Dec 16, 2024
32dcabe
chore(directives): implement step-level vars
hiddeco Dec 16, 2024
d502374
feat(directives): filter output for "namespaced" keys
hiddeco Dec 16, 2024
82daebe
fix(ui): type issue, vars cannot be optional
hiddeco Dec 16, 2024
b46b1fd
WIP: magically write output of "namespaced" steps to namespace
hiddeco Dec 16, 2024
5c1422d
feat(chart): add base permissions `(Cluster)PromotionTask`
hiddeco Dec 17, 2024
9ee906a
fix(api): use correct struct for list
hiddeco Dec 17, 2024
97cb4e6
fix: small bug fixes
hiddeco Dec 17, 2024
cb1907d
fix: ensure (step) vars can access outputs
hiddeco Dec 17, 2024
8d4cae6
fix: add `task-<num>` to reserved aliases
hiddeco Dec 17, 2024
474288f
fix(chart): allow API permissions to `Cluster)PromotionTask`
hiddeco Dec 17, 2024
18a666d
feat: add validation webhook for PromotionTask
hiddeco Dec 18, 2024
82d629c
chore: run codegen
hiddeco Dec 18, 2024
51fc805
fix(chart): add permissions to kargo-admin role
hiddeco Dec 18, 2024
68d62fe
chore: remove redundant test
hiddeco Dec 19, 2024
0891669
chore: tiny bit of `compose-output` documentation
hiddeco Dec 19, 2024
06720fd
chore: move task inflation to mutating webhook
hiddeco Dec 19, 2024
c0f3c90
fix: ensure state is available to var getter
hiddeco Dec 19, 2024
ae40450
fix: evaluate step vars and outputs in indexer
hiddeco Jan 10, 2025
911cc13
refactor: improve inflation of task step vars
hiddeco Jan 10, 2025
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
27 changes: 27 additions & 0 deletions api/v1alpha1/cluster_promotion_task_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package v1alpha1

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

// +kubebuilder:resource:scope=Cluster,shortName={clusterpromotask,clusterpromotasks}
// +kubebuilder:object:root=true
// +kubebuilder:printcolumn:name=Age,type=date,JSONPath=`.metadata.creationTimestamp`

type ClusterPromotionTask struct {
Copy link
Member

@jessesuen jessesuen Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I know ClusterPromotionTask is technically accurate, I wonder if we want to term this "GlobalPromotionTask". We already refer to credentials and ServiceAccounts that are to be used in a global capacity as "global" credentials and global serviceaccounts, and this would be along those lines.

The "cluster" is less meaningful since kargo is not really used in a workload cluster.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jessesuen I wonder if I can offer a counterpoint. The "global" things we have now (and I don't love that term) such as credentials and SAs are things incapable of living in a cluster scope. Putting them in designated namespaces is essentially a workaround.

Here, we have the opportunity to handle things in a more conventional manner. When a CRD whose instances will exist in the cluster scope needs to be differentiated from a namespace-scoped counterpart, I think "Cluster____" is a very widely observed convention that people will understand intuitively.

metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Spec describes the desired transition of a specific Stage into a specific
// Freight.
//
// +kubebuilder:validation:Required
Spec PromotionTaskSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
}

// +kubebuilder:object:root=true

// ClusterPromotionTaskList contains a list of PromotionTasks.
type ClusterPromotionTaskList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []ClusterPromotionTask `json:"items" protobuf:"bytes,2,rep,name=items"`
}
2,350 changes: 1,894 additions & 456 deletions api/v1alpha1/generated.pb.go

Large diffs are not rendered by default.

88 changes: 88 additions & 0 deletions api/v1alpha1/generated.proto

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

4 changes: 4 additions & 0 deletions api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var (
// addKnownTypes adds the set of types defined in this package to the supplied scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(GroupVersion,
&ClusterPromotionTask{},
&ClusterPromotionTaskList{},
&Freight{},
&FreightList{},
&Stage{},
Expand All @@ -35,6 +37,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ProjectList{},
&Promotion{},
&PromotionList{},
&PromotionTask{},
&PromotionTaskList{},
&Warehouse{},
&WarehouseList{},
)
Expand Down
44 changes: 44 additions & 0 deletions api/v1alpha1/promotion_task_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:resource:shortName={promotask,promotasks}
// +kubebuilder:object:root=true
// +kubebuilder:printcolumn:name=Age,type=date,JSONPath=`.metadata.creationTimestamp`

type PromotionTask struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Spec describes the composition of a PromotionTask, including the
// variables available to the task and the steps.
//
// +kubebuilder:validation:Required
Spec PromotionTaskSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
}

type PromotionTaskSpec struct {
// Vars specifies the variables available to the PromotionTask. The
// values of these variables are the default values that can be
// overridden by the step referencing the task.
Vars []PromotionVariable `json:"vars,omitempty" protobuf:"bytes,1,rep,name=vars"`
// Steps specifies the directives to be executed as part of this
// PromotionTask. The steps as defined here are inflated into a
// Promotion when it is built from a PromotionTemplate.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:items:XValidation:message="PromotionTask step must have uses set and must not reference another task",rule="has(self.uses) && !has(self.task)"
Steps []PromotionStep `json:"steps" protobuf:"bytes,2,rep,name=steps"`
}

// +kubebuilder:object:root=true

// PromotionTaskList contains a list of PromotionTasks.
type PromotionTaskList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []PromotionTask `json:"items" protobuf:"bytes,2,rep,name=items"`
}
57 changes: 54 additions & 3 deletions api/v1alpha1/promotion_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1alpha1

import (
"fmt"
"time"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
Expand Down Expand Up @@ -80,21 +81,30 @@
// applies. The Stage referenced by this field MUST be in the same
// namespace as the Promotion.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
Stage string `json:"stage" protobuf:"bytes,1,opt,name=stage"`
// Freight specifies the piece of Freight to be promoted into the Stage
// referenced by the Stage field.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
Freight string `json:"freight" protobuf:"bytes,2,opt,name=freight"`
// Vars is a list of variables that can be referenced by expressions in
// promotion steps.
Vars []PromotionVariable `json:"vars,omitempty" protobuf:"bytes,4,rep,name=vars"`
// Steps specifies the directives to be executed as part of this Promotion.
// The order in which the directives are executed is the order in which they
// are listed in this field.
Steps []PromotionStep `json:"steps,omitempty" protobuf:"bytes,3,rep,name=steps"`
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:items:XValidation:message="Promotion step must have uses set and must not reference a task",rule="has(self.uses) && !has(self.task)"
Steps []PromotionStep `json:"steps" protobuf:"bytes,3,rep,name=steps"`
}

// PromotionVariable describes a single variable that may be referenced by
Expand All @@ -108,7 +118,25 @@
// Value is the value of the variable. It is allowed to utilize expressions
// in the value.
// See https://docs.kargo.io/references/expression-language for details.
Value string `json:"value" protobuf:"bytes,2,opt,name=value"`
Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"`
}

// PromotionTaskReference describes a reference to a PromotionTask.
type PromotionTaskReference struct {
// Name is the name of the (Cluster)PromotionTask.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`

// Kind is the type of the PromotionTask. Can be either PromotionTask or
// ClusterPromotionTask, default is PromotionTask.
//
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Enum=PromotionTask;ClusterPromotionTask
Kind string `json:"kind,omitempty" protobuf:"bytes,2,opt,name=kind"`
}

// PromotionStepRetry describes the retry policy for a PromotionStep.
Expand Down Expand Up @@ -171,19 +199,42 @@
type PromotionStep struct {
// Uses identifies a runner that can execute this step.
//
// +kubebuilder:validation:Optional
// +kubebuilder:validation:MinLength=1
Uses string `json:"uses" protobuf:"bytes,1,opt,name=uses"`
Uses string `json:"uses,omitempty" protobuf:"bytes,1,opt,name=uses"`
// Task is a reference to a PromotionTask that should be inflated into a
// Promotion when it is built from a PromotionTemplate.
Task *PromotionTaskReference `json:"task,omitempty" protobuf:"bytes,5,opt,name=task"`
// As is the alias this step can be referred to as.
As string `json:"as,omitempty" protobuf:"bytes,2,opt,name=as"`
// Retry is the retry policy for this step.
Retry *PromotionStepRetry `json:"retry,omitempty" protobuf:"bytes,4,opt,name=retry"`
// Vars is a list of variables that can be referenced by expressions in
// the step's Config. The values override the values specified in the
// PromotionSpec.
Vars []PromotionVariable `json:"vars,omitempty" protobuf:"bytes,6,rep,name=vars"`
// Config is opaque configuration for the PromotionStep that is understood
// only by each PromotionStep's implementation. It is legal to utilize
// expressions in defining values at any level of this block.
// See https://docs.kargo.io/references/expression-language for details.
Config *apiextensionsv1.JSON `json:"config,omitempty" protobuf:"bytes,3,opt,name=config"`
}

// GetAlias returns the As field, or a default value in the form of "step-<i>"
// or "task-<i>" if the As field is empty. The index i is provided as an
// argument to this method and should be the index of the PromotionStep in the
// list it belongs to.
func (s *PromotionStep) GetAlias(i int) string {
switch {
case s.As != "":
return s.As
case s.Task != nil:
return fmt.Sprintf("task-%d", i)
default:
return fmt.Sprintf("step-%d", i)

Check warning on line 234 in api/v1alpha1/promotion_types.go

View check run for this annotation

Codecov / codecov/patch

api/v1alpha1/promotion_types.go#L227-L234

Added lines #L227 - L234 were not covered by tests
}
}

// PromotionStatus describes the current state of the transition represented by
// a Promotion.
type PromotionStatus struct {
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/stage_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ type PromotionTemplateSpec struct {
// are listed in this field.
//
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:items:XValidation:message="PromotionTemplate step must have exactly one of uses or task set",rule="(has(self.uses) ? !has(self.task) : has(self.task))"
Steps []PromotionStep `json:"steps,omitempty" protobuf:"bytes,1,rep,name=steps"`
}

Expand Down
Loading
Loading