Support stack references in Go SDK (#3829)
This commit is contained in:
parent
63be1b5d21
commit
411f1a179a
|
@ -1,6 +1,10 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
## HEAD (unreleased)
|
||||||
|
- Support stack references in the Go SDK.
|
||||||
|
[#3829](https://github.com/pulumi/pulumi/pull/3829)
|
||||||
|
|
||||||
## 1.10.0 (2020-02-05)
|
## 1.10.0 (2020-02-05)
|
||||||
- Avoid writing checkpoints to backend storage in common case where no changes are being made.
|
- Avoid writing checkpoints to backend storage in common case where no changes are being made.
|
||||||
[#3860](https://github.com/pulumi/pulumi/pull/3860)
|
[#3860](https://github.com/pulumi/pulumi/pull/3860)
|
||||||
|
|
56
sdk/go/pulumi/stack_reference.go
Normal file
56
sdk/go/pulumi/stack_reference.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package pulumi
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// StackReference manages a reference to a Pulumi stack.
|
||||||
|
type StackReference struct {
|
||||||
|
CustomResourceState
|
||||||
|
|
||||||
|
// Name is in the form "Org/Program/Stack"
|
||||||
|
Name StringOutput `pulumi:"name"`
|
||||||
|
// Outputs resolves with exports from the named stack
|
||||||
|
Outputs MapOutput `pulumi:"outputs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StackReference) GetOutput(name StringInput) AnyOutput {
|
||||||
|
return All(name, s.Outputs).
|
||||||
|
ApplyT(func(args []interface{}) interface{} {
|
||||||
|
n, outs := args[0].(string), args[1].(map[string]interface{})
|
||||||
|
return outs[n]
|
||||||
|
}).(AnyOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stackReferenceArgs struct {
|
||||||
|
Name string `pulumi:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackReferenceArgs is the input to NewStackReference that allows specifying a stack name
|
||||||
|
type StackReferenceArgs struct {
|
||||||
|
// Name is in the form "Org/Program/Stack"
|
||||||
|
Name StringInput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (StackReferenceArgs) ElementType() reflect.Type {
|
||||||
|
return reflect.TypeOf((*stackReferenceArgs)(nil)).Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStackReference creates a stack reference that makes available outputs from the specified stack
|
||||||
|
func NewStackReference(ctx *Context, name string, args *StackReferenceArgs,
|
||||||
|
opts ...ResourceOption) (*StackReference, error) {
|
||||||
|
|
||||||
|
if args == nil {
|
||||||
|
args = &StackReferenceArgs{}
|
||||||
|
}
|
||||||
|
if args.Name == nil {
|
||||||
|
args.Name = StringInput(String(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
id := args.Name.ToStringOutput().ApplyT(func(s string) ID { return ID(s) }).(IDOutput)
|
||||||
|
|
||||||
|
var ref StackReference
|
||||||
|
if err := ctx.ReadResource("pulumi:pulumi:StackReference", name, id, args, &ref, opts...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ref, nil
|
||||||
|
}
|
59
sdk/go/pulumi/stack_reference_test.go
Normal file
59
sdk/go/pulumi/stack_reference_test.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package pulumi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/pkg/resource"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStackReference(t *testing.T) {
|
||||||
|
var resName string
|
||||||
|
outputs := map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": []interface{}{"qux"},
|
||||||
|
"zed": map[string]interface{}{
|
||||||
|
"alpha": "beta",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mocks := &testMonitor{
|
||||||
|
NewResourceF: func(typeToken, name string, inputs resource.PropertyMap,
|
||||||
|
provider, id string) (string, resource.PropertyMap, error) {
|
||||||
|
assert.Equal(t, "pulumi:pulumi:StackReference", typeToken)
|
||||||
|
assert.Equal(t, resName, name)
|
||||||
|
assert.True(t, inputs.DeepEquals(resource.NewPropertyMapFromMap(map[string]interface{}{
|
||||||
|
"name": "stack",
|
||||||
|
})))
|
||||||
|
assert.Equal(t, "", provider)
|
||||||
|
assert.Equal(t, inputs["name"].StringValue(), id)
|
||||||
|
return inputs["name"].StringValue(), resource.NewPropertyMapFromMap(map[string]interface{}{
|
||||||
|
"name": "stack",
|
||||||
|
"outputs": outputs,
|
||||||
|
}), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := RunErr(func(ctx *Context) error {
|
||||||
|
resName = "stack"
|
||||||
|
ref0, err := NewStackReference(ctx, resName, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, _, err = await(ref0.ID())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
resName = "stack2"
|
||||||
|
ref1, err := NewStackReference(ctx, resName, &StackReferenceArgs{Name: String("stack")})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
outs0, _, err := await(ref0.Outputs)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, outputs, outs0)
|
||||||
|
zed0, _, err := await(ref0.GetOutput(String("zed")))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, outputs["zed"], zed0)
|
||||||
|
outs1, _, err := await(ref1.Outputs)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, outputs, outs1)
|
||||||
|
zed1, _, err := await(ref1.GetOutput(String("zed")))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, outputs["zed"], zed1)
|
||||||
|
return nil
|
||||||
|
}, WithMocks("project", "stack", mocks))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -1180,6 +1180,31 @@ func TestStackReferenceDotnet(t *testing.T) {
|
||||||
integration.ProgramTest(t, opts)
|
integration.ProgramTest(t, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that stack references work in Go.
|
||||||
|
func TestStackReferenceGo(t *testing.T) {
|
||||||
|
if runtime.GOOS == WindowsOS {
|
||||||
|
t.Skip("Temporarily skipping test on Windows - pulumi/pulumi#3811")
|
||||||
|
}
|
||||||
|
if owner := os.Getenv("PULUMI_TEST_OWNER"); owner == "" {
|
||||||
|
t.Skipf("Skipping: PULUMI_TEST_OWNER is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &integration.ProgramTestOptions{
|
||||||
|
Dir: filepath.Join("stack_reference", "go"),
|
||||||
|
Quick: true,
|
||||||
|
Config: map[string]string{
|
||||||
|
"org": os.Getenv("PULUMI_TEST_OWNER"),
|
||||||
|
},
|
||||||
|
EditDirs: []integration.EditDir{
|
||||||
|
{
|
||||||
|
Dir: "step1",
|
||||||
|
Additive: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
integration.ProgramTest(t, opts)
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that we issue an error if we fail to locate the Python command when running
|
// Tests that we issue an error if we fail to locate the Python command when running
|
||||||
// a Python example.
|
// a Python example.
|
||||||
func TestPython3NotInstalled(t *testing.T) {
|
func TestPython3NotInstalled(t *testing.T) {
|
||||||
|
|
3
tests/integration/stack_reference/go/Pulumi.yaml
Normal file
3
tests/integration/stack_reference/go/Pulumi.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
name: stack_reference_go
|
||||||
|
description: A simple go program that has a stack reference.
|
||||||
|
runtime: go
|
30
tests/integration/stack_reference/go/main.go
Normal file
30
tests/integration/stack_reference/go/main.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2016-2020, Pulumi Corporation. All rights reserved.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/sdk/go/pulumi"
|
||||||
|
"github.com/pulumi/pulumi/sdk/go/pulumi/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pulumi.Run(func(ctx *pulumi.Context) error {
|
||||||
|
cfg := config.New(ctx, ctx.Project())
|
||||||
|
|
||||||
|
org := cfg.Require("org")
|
||||||
|
slug := fmt.Sprintf("%v/%v/%v", org, ctx.Project(), ctx.Stack())
|
||||||
|
_, err := pulumi.NewStackReference(ctx, slug, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error reading stack reference.")
|
||||||
|
}
|
||||||
|
ctx.Export("val",
|
||||||
|
pulumi.StringArray([]pulumi.StringInput{pulumi.String("a"), pulumi.String("b")}))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
48
tests/integration/stack_reference/go/step1/main.go
Normal file
48
tests/integration/stack_reference/go/step1/main.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2016-2020, Pulumi Corporation. All rights reserved.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/sdk/go/pulumi"
|
||||||
|
"github.com/pulumi/pulumi/sdk/go/pulumi/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pulumi.Run(func(ctx *pulumi.Context) error {
|
||||||
|
|
||||||
|
cfg := config.New(ctx, ctx.Project())
|
||||||
|
|
||||||
|
org := cfg.Require("org")
|
||||||
|
slug := fmt.Sprintf("%v/%v/%v", org, ctx.Project(), ctx.Stack())
|
||||||
|
stackRef, err := pulumi.NewStackReference(ctx, slug, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Error reading stack reference.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val := pulumi.StringArrayOutput(stackRef.GetOutput(pulumi.String("val")))
|
||||||
|
|
||||||
|
errChan := make(chan error)
|
||||||
|
results := make(chan []string)
|
||||||
|
|
||||||
|
_ = val.ApplyStringArray(func(v []string) ([]string, error) {
|
||||||
|
if len(v) != 2 || v[0] != "a" || v[1] != "b" {
|
||||||
|
errChan <- errors.Errorf("Invalid result")
|
||||||
|
return nil, errors.Errorf("Invalid result")
|
||||||
|
}
|
||||||
|
results <- v
|
||||||
|
return v, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-errChan:
|
||||||
|
return err
|
||||||
|
case <-results:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue