Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit 5491d08

Browse files
committed
Add support for outputName, outputNamespace overrides.
1 parent 4cf134f commit 5491d08

File tree

4 files changed

+86
-12
lines changed

4 files changed

+86
-12
lines changed

api/v1alpha1/workspace_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ type WorkspaceSpec struct {
126126
// SSH Key ID. This key must already exist in the TF Cloud organization. This can either be the user assigned name of the SSH Key, or the system assigned ID.
127127
// +optional
128128
SSHKeyID string `json:"sshKeyID,omitempty"`
129+
// Overrides default output name. Default output name is `<workspaceName>-outputs`.
130+
// +optional
131+
OutputName string `json:"outputName,omitempty"`
132+
// Overrides default output namespace. Default namespace is the same namespace as the workspace.
133+
// +optional
134+
OutputNamespace string `json:"outputNamespace,omitempty"`
129135
// Outputs denote outputs wanted
130136
// +optional
131137
Outputs []*OutputSpec `json:"outputs,omitempty"`
@@ -157,6 +163,14 @@ type WorkspaceStatus struct {
157163
RunID string `json:"runID"`
158164
// Configuration Version ID
159165
ConfigVersionID string `json:"configVersionID"`
166+
// Current output name
167+
// +optional
168+
// +nullable
169+
OutputName string `json:"outputName"`
170+
// Current output namespace
171+
// +optional
172+
// +nullable
173+
OutputNamespace string `json:"outputNamespace"`
160174
// Outputs from state file
161175
// +optional
162176
Outputs []*OutputStatus `json:"outputs,omitempty"`

config/crd/bases/app.terraform.io_workspaces.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ spec:
104104
organization:
105105
description: Terraform Cloud organization
106106
type: string
107+
outputName:
108+
description: Overrides default output name. Default output name is <workspaceName>-outputs.
109+
type: string
110+
outputNamespace:
111+
description: Overrides default output namespace. Default namespace is the same namespace as the workspace.
112+
type: string
107113
outputs:
108114
description: Outputs denote outputs wanted
109115
items:

workspacehelper/k8s_configmap.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package workspacehelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"reflect"
87

98
"github.com/hashicorp/terraform-k8s/api/v1alpha1"
@@ -116,13 +115,53 @@ func outputsToMap(outputs []*v1alpha1.OutputStatus) map[string][]byte {
116115
return data
117116
}
118117

118+
// CleanPreviousSecretOutputsIfChanged cleans previous secret if output has changed
119+
func (r *WorkspaceHelper) CleanPreviousSecretOutputsIfChanged(outputName string, outputNamespace string, status *v1alpha1.WorkspaceStatus) error {
120+
currentName := status.OutputName
121+
currentNamespace := status.OutputNamespace
122+
123+
// no previous name was set, do nothing
124+
if currentName == "" || currentNamespace == "" {
125+
return nil
126+
}
127+
128+
// no changes to name/namespace
129+
if currentName == outputName && currentNamespace == outputNamespace {
130+
return nil
131+
}
132+
133+
// attempt to cleanup whatever is configured, if it exists
134+
r.reqLogger.Info("Terraform Output Secret name has changed. Removing previous version.")
135+
found := &corev1.Secret{}
136+
137+
err := r.client.Get(context.TODO(), types.NamespacedName{Name: currentName, Namespace: currentNamespace}, found)
138+
if err != nil && k8serrors.IsNotFound(err) {
139+
// resource already removed, do nothing
140+
return nil
141+
} else if err != nil {
142+
return err
143+
}
144+
145+
if err := r.client.Delete(context.TODO(), found); err != nil {
146+
// unable to remove object
147+
return err
148+
}
149+
150+
return nil
151+
}
152+
119153
// UpsertSecretOutputs creates a Secret for the outputs
120-
func (r *WorkspaceHelper) UpsertSecretOutputs(w *v1alpha1.Workspace, outputs []*v1alpha1.OutputStatus) error {
154+
func (r *WorkspaceHelper) UpsertSecretOutputs(outputName string, outputNamespace string, w *v1alpha1.Workspace) error {
121155
found := &corev1.Secret{}
122-
outputName := fmt.Sprintf("%s-outputs", w.Name)
123-
err := r.client.Get(context.TODO(), types.NamespacedName{Name: outputName, Namespace: w.Namespace}, found)
156+
157+
if err := r.CleanPreviousSecretOutputsIfChanged(outputName, outputNamespace, &w.Status); err != nil {
158+
r.reqLogger.Error(err, "Failed to clean previous output Secret")
159+
return err
160+
}
161+
162+
err := r.client.Get(context.TODO(), types.NamespacedName{Name: outputName, Namespace: outputNamespace}, found)
124163
if err != nil && k8serrors.IsNotFound(err) {
125-
secret := secretForOutputs(outputName, w.Namespace, outputs)
164+
secret := secretForOutputs(outputName, outputNamespace, w.Status.Outputs)
126165
err = controllerutil.SetControllerReference(w, secret, r.scheme)
127166
if err != nil {
128167
return err
@@ -138,12 +177,12 @@ func (r *WorkspaceHelper) UpsertSecretOutputs(w *v1alpha1.Workspace, outputs []*
138177
return err
139178
}
140179

141-
currentOutputs := outputsToMap(outputs)
180+
currentOutputs := outputsToMap(w.Status.Outputs)
142181
if !reflect.DeepEqual(found.Data, currentOutputs) {
143182
r.reqLogger.Info("Updating secrets", "name", outputName)
144183
found.Data = currentOutputs
145184
if err := r.client.Update(context.TODO(), found); err != nil {
146-
r.reqLogger.Error(err, "Failed to update output secrets", "Namespace", w.Namespace, "Name", outputName)
185+
r.reqLogger.Error(err, "Failed to update output secrets", "Namespace", outputNamespace, "Name", outputName)
147186
return err
148187
}
149188
return nil

workspacehelper/workspace_helper.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,26 @@ func (r *WorkspaceHelper) processFinishedRun(instance *appv1alpha1.Workspace) er
244244
return err
245245
}
246246

247-
if !reflect.DeepEqual(outputs, instance.Status.Outputs) {
247+
outputName := fmt.Sprintf("%s-outputs", instance.Name)
248+
if instance.Spec.OutputName != "" {
249+
outputName = instance.Spec.OutputName
250+
}
251+
252+
outputNamespace := instance.Namespace
253+
if instance.Spec.OutputNamespace != "" {
254+
outputNamespace = instance.Spec.OutputNamespace
255+
}
256+
257+
if err = r.UpsertSecretOutputs(outputName, outputNamespace, instance); err != nil {
258+
r.reqLogger.Error(err, "Error with creating Secret for Terraform Outputs")
259+
return err
260+
}
261+
262+
if !reflect.DeepEqual(outputs, instance.Status.Outputs) || instance.Status.OutputName != outputName || instance.Status.OutputNamespace != outputNamespace {
248263
instance.Status.Outputs = outputs
264+
instance.Status.OutputName = outputName
265+
instance.Status.OutputNamespace = outputNamespace
266+
249267
err := r.client.Status().Update(context.TODO(), instance)
250268
if err != nil {
251269
r.reqLogger.Error(err, "Failed to update output status")
@@ -256,10 +274,7 @@ func (r *WorkspaceHelper) processFinishedRun(instance *appv1alpha1.Workspace) er
256274
r.recorder.Event(instance, corev1.EventTypeNormal, "WorkspaceEvent",
257275
fmt.Sprintf("Updated outputs for run %s", instance.Status.RunID))
258276
}
259-
if err = r.UpsertSecretOutputs(instance, instance.Status.Outputs); err != nil {
260-
r.reqLogger.Error(err, "Error with creating ConfigMap for Terraform Outputs")
261-
return err
262-
}
277+
263278
return nil
264279
}
265280

0 commit comments

Comments
 (0)