Support stack references in Go SDK (#3829)
This commit is contained in:
parent
63be1b5d21
commit
411f1a179a
|
@ -1,6 +1,10 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
## HEAD (unreleased)
|
||||
- Support stack references in the Go SDK.
|
||||
[#3829](https://github.com/pulumi/pulumi/pull/3829)
|
||||
|
||||
## 1.10.0 (2020-02-05)
|
||||
- Avoid writing checkpoints to backend storage in common case where no changes are being made.
|
||||
[#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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// a Python example.
|
||||
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