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

🚀 Add Workspace Variable Set Support #497

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
25 changes: 25 additions & 0 deletions api/v1alpha2/workspace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,13 @@ type WorkspaceSpec struct {
//
//+optional
Project *WorkspaceProject `json:"project,omitempty"`
// Variable set allows a group of variables to be applied to a workspace.
// Each entry includes a name and an ID.
sheneska marked this conversation as resolved.
Show resolved Hide resolved
//
//More information
// -https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
// +optional
VariableSets []WorkspaceVariableSet `json:"variableSets,omitempty"`
}

type PlanStatus struct {
Expand Down Expand Up @@ -669,6 +676,24 @@ type WorkspaceList struct {
Items []Workspace `json:"items"`
}

type WorkspaceVariableSet struct {
// Variable Set ID
// Must match pattern: `varset-[a-zA-Z0-9]+$`
//More information:
// -https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
//
//+kubebuilder:validation:Pattern:="varset-[a-zA-Z0-9]+$"
//+optional
ID string `json:"id,omitempty"`
// Variable Set Name.
//More information:
// -https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
//
//+kubebuilder:validation:MinLength:=1
//+optional
Name string `json:"name,omitempty"`
}

func init() {
SchemeBuilder.Register(&Workspace{}, &WorkspaceList{})
}
22 changes: 22 additions & 0 deletions api/v1alpha2/workspace_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func (w *Workspace) ValidateSpec() error {
allErrs = append(allErrs, w.validateSpecProject()...)
allErrs = append(allErrs, w.validateSpecTerraformVariables()...)
allErrs = append(allErrs, w.validateSpecEnvironmentVariables()...)
allErrs = append(allErrs, w.validateSpecVariableSets()...)

if len(allErrs) == 0 {
return nil
Expand Down Expand Up @@ -568,6 +569,27 @@ func (w *Workspace) validateSpecEnvironmentVariables() field.ErrorList {
return validateSpecVariables(field.NewPath("spec").Child("environmentVariables"), spec)
}

func (w *Workspace) validateSpecVariableSets() field.ErrorList {
sheneska marked this conversation as resolved.
Show resolved Hide resolved
allErrs := field.ErrorList{}
spec := w.Spec.VariableSets

for _, varSet := range spec {

f := field.NewPath("spec").Child("variableSets")

// Check if both ID and Name are set
if varSet.ID != "" && varSet.Name != "" {
// Both ID and Name cannot be set
allErrs = append(allErrs, field.Required(f, "Only one of ID or Name should be set."))
} else if varSet.ID == "" && varSet.Name == "" {
// At least one, either ID or Name must be set
allErrs = append(allErrs, field.Required(f, "At least one must be set."))
}
}

return allErrs
}

// TODO:Validation
//
// + Tags duplicate: spec.tags[]
Expand Down
68 changes: 68 additions & 0 deletions api/v1alpha2/workspace_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1038,3 +1038,71 @@ func TestValidateWorkspaceSpecVariables(t *testing.T) {
})
}
}

func TestValidateWorkspaceSpecVariableSets(t *testing.T) {
t.Parallel()

// Success Cases: Valid combinations of ID and Name
successCases := map[string]Workspace{
"HasID": {
Spec: WorkspaceSpec{
VariableSets: []WorkspaceVariableSet{
{
ID: "this", // Only ID is set
},
},
},
},
"HasName": {
Spec: WorkspaceSpec{
VariableSets: []WorkspaceVariableSet{
{
Name: "this", // Only Name is set
},
},
},
},
}

// Run Success Test Cases
for n, c := range successCases {
t.Run(n, func(t *testing.T) {
if errs := c.validateSpecVariableSets(); len(errs) != 0 {
t.Errorf("Unexpected validation errors: %v", errs)
}
})
}

// Error Cases: Invalid combinations of ID and Name
errorCases := map[string]Workspace{
sheneska marked this conversation as resolved.
Show resolved Hide resolved
"HasEmptyIDandEmptyName": {
Spec: WorkspaceSpec{
VariableSets: []WorkspaceVariableSet{
{
ID: "",
Name: "", // Neither ID nor Name is set (invalid)
},
},
},
},

"HasBothIDandName": {
Spec: WorkspaceSpec{
VariableSets: []WorkspaceVariableSet{
{
ID: "thisID", // Both ID and Name are set (invalid)
Name: "thisName",
},
},
},
},
}

for n, c := range errorCases {
t.Run(n, func(t *testing.T) {
if errs := c.validateSpecVariableSets(); len(errs) == 0 {
t.Error("Unexpected failure, at least one error is expected")
}
})
}
}
20 changes: 20 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,33 @@ spec:
required:
- secretKeyRef
type: object
variableSets:
description: |-
Variable set allows a group of variables to be applied to a workspace.
Each entry includes a name and an ID.


More information
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
items:
properties:
id:
description: |-
Variable Set ID
Must match pattern: `varset-[a-zA-Z0-9]+$`
More information:
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
pattern: varset-[a-zA-Z0-9]+$
type: string
name:
description: |-
Variable Set Name.
More information:
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
minLength: 1
type: string
type: object
type: array
versionControl:
description: |-
Settings for the workspace's VCS repository, enabling the UI/VCS-driven run workflow.
Expand Down
27 changes: 27 additions & 0 deletions config/crd/bases/app.terraform.io_workspaces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,33 @@ spec:
required:
- secretKeyRef
type: object
variableSets:
description: |-
Variable set allows a group of variables to be applied to a workspace.
Each entry includes a name and an ID.


More information
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
items:
properties:
id:
description: |-
Variable Set ID
Must match pattern: `varset-[a-zA-Z0-9]+$`
More information:
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
pattern: varset-[a-zA-Z0-9]+$
type: string
name:
description: |-
Variable Set Name.
More information:
-https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets#apply-variable-set-to-workspaces
minLength: 1
type: string
type: object
type: array
versionControl:
description: |-
Settings for the workspace's VCS repository, enabling the UI/VCS-driven run workflow.
Expand Down
12 changes: 11 additions & 1 deletion controllers/workspace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ func (r *WorkspaceReconciler) reconcileWorkspace(ctx context.Context, w *workspa
w.log.Info("Reconcile Variables", "msg", "successfully reconcilied variables")
r.Recorder.Eventf(&w.instance, corev1.EventTypeNormal, "ReconcileVariables", "Reconcilied variables in workspace ID %s", w.instance.Status.WorkspaceID)

// Reconcile Variable Sets
err = r.reconcileVariableSets(ctx, w, workspace)
if err != nil {
w.log.Error(err, "Reconcile Variable Sets", "msg", fmt.Sprintf("failed to reconcile variable sets in workspace ID %s", w.instance.Status.WorkspaceID))
r.Recorder.Eventf(&w.instance, corev1.EventTypeWarning, "ReconcileVariableSets", "Failed to reconcile variable sets in workspace ID %s", w.instance.Status.WorkspaceID)
return err
}
w.log.Info("Reconcile Variable Sets", "msg", "successfully reconciled variable sets")
r.Recorder.Eventf(&w.instance, corev1.EventTypeNormal, "ReconcileVariableSets", "Successfully reconciled variable sets in workspace ID %s", w.instance.Status.WorkspaceID)

// Reconcile Run Triggers
err = r.reconcileRunTriggers(ctx, w)
if err != nil {
Expand Down Expand Up @@ -631,7 +641,7 @@ func (r *WorkspaceReconciler) reconcileWorkspace(ctx context.Context, w *workspa
w.log.Info("Reconcile Notifications", "msg", "successfully reconcilied notifications")
r.Recorder.Eventf(&w.instance, corev1.EventTypeNormal, "ReconcileNotifications", "Reconcilied notifications in workspace ID %s", w.instance.Status.WorkspaceID)

// Reconsile Runs (Status)
// Reconcile Runs (Status)
// This reconciliation should always happen before `reconcileOutputs`
err = r.reconcileRuns(ctx, w, workspace)
if err != nil {
Expand Down
Loading
Loading