Skip to content

Commit

Permalink
Add backend configuration
Browse files Browse the repository at this point in the history
Adds a top level `backend` field to the Stack CR that allows pointing all operations for the target Stack at the given backend.  In cases where `backend` is set to a non-service backend, the AccessTokenSecret field is also no longer required.

This is dependent on pulumi/pulumi#5789, and cannot be merged until the operator can take a dependency on that change in the core `pulumi` CLI.

Fixes #83.
  • Loading branch information
Luke Hoban committed Nov 20, 2020
1 parent 9bd6bd3 commit f5da3c7
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 20 deletions.
6 changes: 4 additions & 2 deletions deploy/crds/pulumi.com_stacks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ spec:
description: StackSpec defines the desired state of Pulumi Stack being managed by this operator.
properties:
accessTokenSecret:
description: AccessTokenSecret is the name of a secret containing the PULUMI_ACCESS_TOKEN for Pulumi access.
description: (optional) AccessTokenSecret is the name of a secret containing the PULUMI_ACCESS_TOKEN for Pulumi access.
type: string
backend:
description: (optional) Backend is an optional backend URL to use for all Pulumi operations.
type: string
branch:
description: (optional) Branch is the branch name to deploy, either the simple or fully qualified ref name. This is mutually exclusive with the Commit setting. If both are empty, the `master` branch is deployed.
Expand Down Expand Up @@ -89,7 +92,6 @@ spec:
description: Stack is the fully qualified name of the stack to deploy (<org>/<stack>).
type: string
required:
- accessTokenSecret
- projectRepo
- stack
type: object
Expand Down
7 changes: 5 additions & 2 deletions pkg/apis/pulumi/v1alpha1/stack_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import (
type StackSpec struct {
// Auth info:

// AccessTokenSecret is the name of a secret containing the PULUMI_ACCESS_TOKEN for Pulumi access.
AccessTokenSecret string `json:"accessTokenSecret"`
// (optional) AccessTokenSecret is the name of a secret containing the PULUMI_ACCESS_TOKEN for Pulumi access.
AccessTokenSecret string `json:"accessTokenSecret,omitempty"`
// (optional) Envs is an optional array of config maps containing environment variables to set.
Envs []string `json:"envs,omitempty"`
// (optional) SecretEnvs is an optional array of secret names containing environment variables to set.
SecretEnvs []string `json:"envSecrets,omitempty"`

// (optional) Backend is an optional backend URL to use for all Pulumi operations.
Backend string `json:"backend,omitempty"`

// Stack identity:

// Stack is the fully qualified name of the stack to deploy (<org>/<stack>).
Expand Down
38 changes: 23 additions & 15 deletions pkg/controller/stack/stack_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,24 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result,
// indicated by the deletion timestamp being set.
isStackMarkedToBeDeleted := instance.GetDeletionTimestamp() != nil

// Fetch the API token from the named secret.
secret := &corev1.Secret{}
if err = r.client.Get(context.TODO(),
types.NamespacedName{Name: stack.AccessTokenSecret, Namespace: request.Namespace}, secret); err != nil {
reqLogger.Error(err, "Could not find secret for Pulumi API access",
"Namespace", request.Namespace, "Stack.AccessTokenSecret", stack.AccessTokenSecret)
return reconcile.Result{}, err
}
var accessToken string
if stack.AccessTokenSecret != "" {
// Fetch the API token from the named secret.
secret := &corev1.Secret{}
if err = r.client.Get(context.TODO(),
types.NamespacedName{Name: stack.AccessTokenSecret, Namespace: request.Namespace}, secret); err != nil {
reqLogger.Error(err, "Could not find secret for Pulumi API access",
"Namespace", request.Namespace, "Stack.AccessTokenSecret", stack.AccessTokenSecret)
return reconcile.Result{}, err
}

accessToken := string(secret.Data["accessToken"])
if accessToken == "" {
err = errors.New("Secret accessToken data is empty")
reqLogger.Error(err, "Illegal empty secret accessToken data for Pulumi API access",
"Namespace", request.Namespace, "Stack.AccessTokenSecret", stack.AccessTokenSecret)
return reconcile.Result{}, err
accessToken = string(secret.Data["accessToken"])
if accessToken == "" {
err = errors.New("Secret accessToken data is empty")
reqLogger.Error(err, "Illegal empty secret accessToken data for Pulumi API access",
"Namespace", request.Namespace, "Stack.AccessTokenSecret", stack.AccessTokenSecret)
return reconcile.Result{}, err
}
}

// Create a new reconciliation session.
Expand Down Expand Up @@ -522,7 +525,12 @@ func (sess *reconcileStackSession) SetupPulumiWorkdir(gitAuth *auto.GitAuth) err
if err != nil {
return errors.Wrap(err, "failed to create local workspace")
}
w.SetEnvVar("PULUMI_ACCESS_TOKEN", sess.accessToken)
if sess.stack.Backend != "" {
w.SetEnvVar("PULUMI_BACKEND_URL", sess.stack.Backend)
}
if sess.accessToken != "" {
w.SetEnvVar("PULUMI_ACCESS_TOKEN", sess.accessToken)
}

// Create a new stack if the stack does not already exist, or fall back to
// selecting the existing stack. If the stack does not exist, it will be created and selected.
Expand Down
10 changes: 9 additions & 1 deletion test/stack_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/base32"
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
Expand Down Expand Up @@ -120,9 +121,16 @@ var _ = Describe("Stack Controller", func() {
stackName := fmt.Sprintf("%s/s3-op-project/dev-%s", stackOrg, randString())
fmt.Fprintf(GinkgoWriter, "Stack.Name: %s\n", stackName)

// Use a local backend for this test
backendDir, err := ioutil.TempDir("", "")
if err != nil {
Fail("Could not create backend directory")
}
defer os.RemoveAll(backendDir)

// Define the stack spec
spec := pulumiv1alpha1.StackSpec{
AccessTokenSecret: pulumiAPISecret.ObjectMeta.Name,
Backend: fmt.Sprintf("file://%s", backendDir),
SecretEnvs: []string{
pulumiAWSSecret.ObjectMeta.Name,
},
Expand Down

0 comments on commit f5da3c7

Please sign in to comment.