Allow passing a non-default secrets provider to AutomationAPI (#5320)
This commit is contained in:
parent
49152e6331
commit
9a74064d2b
|
@ -23,6 +23,9 @@ CHANGELOG
|
|||
|
||||
- Python SDK: Add support for `Sequence[T]` for array types
|
||||
[#5282](https://github.com/pulumi/pulumi/pull/5282)
|
||||
|
||||
- feat(autoapi): Add support for non default secret providers in local workspaces
|
||||
[#5320](https://github.com/pulumi/pulumi/pull/5320)
|
||||
|
||||
## 2.9.2 (2020-08-31)
|
||||
|
||||
|
|
|
@ -312,6 +312,28 @@ func ExampleNewLocalWorkspace() {
|
|||
_, _ = NewLocalWorkspace(ctx, wd, ph, proj)
|
||||
}
|
||||
|
||||
func ExampleLocalWorkspace_secretsProvider() {
|
||||
ctx := context.Background()
|
||||
// WorkDir sets the working directory for the LocalWorkspace. The workspace will look for a default
|
||||
// project settings file (Pulumi.yaml) in this location for information about the Pulumi program.
|
||||
wd := WorkDir(filepath.Join("..", "path", "to", "pulumi", "project"))
|
||||
// PulumiHome customizes the location of $PULUMI_HOME where metadata is stored and plugins are installed.
|
||||
ph := PulumiHome(filepath.Join("~", ".pulumi"))
|
||||
// Project provides ProjectSettings to set once the workspace is created.
|
||||
proj := Project(workspace.Project{
|
||||
Name: tokens.PackageName("myproject"),
|
||||
Runtime: workspace.NewProjectRuntimeInfo("go", nil),
|
||||
Backend: &workspace.ProjectBackend{
|
||||
URL: "https://url.to.custom.saas.backend.com",
|
||||
},
|
||||
})
|
||||
// Secrets provider provides a way of passing a non-default secrets provider to the
|
||||
// workspace and the stacks created from it. Supported secrets providers are:
|
||||
// `awskms`, `azurekeyvault`, `gcpkms`, `hashivault` and `passphrase`
|
||||
secretsProvider := SecretsProvider("awskms://alias/mysecretkeyalias")
|
||||
_, _ = NewLocalWorkspace(ctx, wd, ph, proj, secretsProvider)
|
||||
}
|
||||
|
||||
func ExampleLocalWorkspace_ListPlugins() {
|
||||
ctx := context.Background()
|
||||
// create a workspace from a local project
|
||||
|
|
|
@ -39,10 +39,11 @@ import (
|
|||
// alter the Workspace Pulumi.yaml file, and setting config on a Stack will modify the Pulumi.<stack>.yaml file.
|
||||
// This is identical to the behavior of Pulumi CLI driven workspaces.
|
||||
type LocalWorkspace struct {
|
||||
workDir string
|
||||
pulumiHome string
|
||||
program pulumi.RunFunc
|
||||
envvars map[string]string
|
||||
workDir string
|
||||
pulumiHome string
|
||||
program pulumi.RunFunc
|
||||
envvars map[string]string
|
||||
secretsProvider string
|
||||
}
|
||||
|
||||
var settingsExtensions = []string{".yaml", ".yml", ".json"}
|
||||
|
@ -136,7 +137,7 @@ func (l *LocalWorkspace) GetConfig(ctx context.Context, fqsn string, key string)
|
|||
if err != nil {
|
||||
return val, errors.Wrapf(err, "could not get config, unable to select stack %s", fqsn)
|
||||
}
|
||||
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "get", key, "--show-secrets", "--json")
|
||||
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "get", key, "--json")
|
||||
if err != nil {
|
||||
return val, newAutoError(errors.Wrap(err, "unable to read config"), stdout, stderr, errCode)
|
||||
}
|
||||
|
@ -330,7 +331,11 @@ func (l *LocalWorkspace) CreateStack(ctx context.Context, fqsn string) error {
|
|||
return errors.Wrap(err, "failed to create stack")
|
||||
}
|
||||
|
||||
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "init", fqsn)
|
||||
args := []string{"stack", "init", fqsn}
|
||||
if l.secretsProvider != "" {
|
||||
args = append(args, fmt.Sprintf("--secrets-provider=%s", l.secretsProvider))
|
||||
}
|
||||
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, args...)
|
||||
if err != nil {
|
||||
return newAutoError(errors.Wrap(err, "failed to create stack"), stdout, stderr, errCode)
|
||||
}
|
||||
|
@ -526,6 +531,11 @@ func NewLocalWorkspace(ctx context.Context, opts ...LocalWorkspaceOption) (Works
|
|||
}
|
||||
}
|
||||
|
||||
// Secrets providers
|
||||
if lwOpts.SecretsProvider != "" {
|
||||
l.secretsProvider = lwOpts.SecretsProvider
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
|
@ -545,6 +555,8 @@ type localWorkspaceOptions struct {
|
|||
Stacks map[string]workspace.ProjectStack
|
||||
// Repo is a git repo with a Pulumi Project to clone into the WorkDir.
|
||||
Repo *GitRepo
|
||||
// Secrets Provider to use with the current Stack
|
||||
SecretsProvider string
|
||||
}
|
||||
|
||||
// LocalWorkspaceOption is used to customize and configure a LocalWorkspace at initialization time.
|
||||
|
@ -621,6 +633,14 @@ func Repo(gitRepo GitRepo) LocalWorkspaceOption {
|
|||
})
|
||||
}
|
||||
|
||||
// SecretsProvider is the secrets provider to use with the current
|
||||
// workspace when interacting with a stack
|
||||
func SecretsProvider(secretsProvider string) LocalWorkspaceOption {
|
||||
return localWorkspaceOption(func(lo *localWorkspaceOptions) {
|
||||
lo.SecretsProvider = secretsProvider
|
||||
})
|
||||
}
|
||||
|
||||
// ValidateFullyQualifiedStackName validates that the fqsn is in the form "org/project/name".
|
||||
func ValidateFullyQualifiedStackName(fqsn string) error {
|
||||
parts := strings.Split(fqsn, "/")
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
@ -30,9 +31,79 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const pulumiOrg = "pulumi"
|
||||
const pulumiOrg = "moolumi"
|
||||
const pName = "testproj"
|
||||
|
||||
func TestWorkspaceSecretsProvider(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
|
||||
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
|
||||
|
||||
// We can't use Workspace EnvVars as the Workspace uses the secrets provider to
|
||||
// create the Stack
|
||||
err := os.Setenv("PULUMI_CONFIG_PASSPHRASE", "password")
|
||||
assert.Nil(t, err, "failed to set EnvVar.")
|
||||
|
||||
// initialize
|
||||
s, err := NewStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
|
||||
c := config.New(ctx, "")
|
||||
ctx.Export("exp_static", pulumi.String("foo"))
|
||||
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
|
||||
ctx.Export("exp_secret", c.GetSecret("buzz"))
|
||||
return nil
|
||||
}, SecretsProvider("passphrase"))
|
||||
if err != nil {
|
||||
t.Errorf("failed to initialize stack, err: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := os.Unsetenv("PULUMI_CONFIG_PASSPHRASE")
|
||||
assert.Nil(t, err, "failed to unset EnvVar.")
|
||||
|
||||
// -- pulumi stack rm --
|
||||
err = s.Workspace().RemoveStack(ctx, s.Name())
|
||||
assert.Nil(t, err, "failed to remove stack. Resources have leaked.")
|
||||
}()
|
||||
|
||||
passwordVal := "Password1234!"
|
||||
err = s.SetConfig(ctx, "MySecretDatabasePassword", ConfigValue{Value: passwordVal, Secret: true})
|
||||
if err != nil {
|
||||
t.Errorf("setConfig failed, err: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// -- pulumi up --
|
||||
res, err := s.Up(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("up failed, err: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Equal(t, "update", res.Summary.Kind)
|
||||
assert.Equal(t, "succeeded", res.Summary.Result)
|
||||
|
||||
// -- get config --
|
||||
conf, err := s.GetConfig(ctx, "MySecretDatabasePassword")
|
||||
if err != nil {
|
||||
t.Errorf("GetConfig failed, err: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
assert.Equal(t, passwordVal, conf.Value)
|
||||
assert.Equal(t, true, conf.Secret)
|
||||
|
||||
// -- pulumi destroy --
|
||||
|
||||
dRes, err := s.Destroy(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("destroy failed, err: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Equal(t, "destroy", dRes.Summary.Kind)
|
||||
assert.Equal(t, "succeeded", dRes.Summary.Result)
|
||||
}
|
||||
|
||||
func TestNewStackLocalSource(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
|
||||
|
|
Loading…
Reference in a new issue