Following up on my previous question regarding Sta...
# golang
s
Following up on my previous question regarding StackReferences in Go, I'm having an issue referencing an array in another stack. I have an array of AWS subnet IDs exported from an infrastructure stack like this:
Copy code
ctx.Export("privSubnetIds", pulumi.StringArray(privSubnetIds))
In another stack that builds on top of that infrastructure stack, I reference the array like this:
Copy code
infra, err := pulumi.NewStackReference(ctx, "org/project/stack", nil)
privSubnets := infra.GetOutput(pulumi.StringArray("privSubnetIds))
I haven't tried to run this yet, because
gopls
inside VS Code is showing errors on the
privSubnets
assignment line & when I try to reference that value inside an
ec2.NewInstance
stanza. I think the error is in the assignment line, but I'm not quite sure how it needs to be changed to work. Any suggestions?
l
What is the type of
privSubnetIds
? Typically when you construct a pulumi array you do so like:
Copy code
pulumi.StringArray{
  pulumi.String("foo"),
  pulumi.String("bar)
}
b
s
@billowy-army-68599 I'll give that a look later this afternoon, thanks!
b
👍 there's a few examples in that repo, if you have any feedback give me a shout
s
Will do, much appreciated!
Sadly, I'm not making any real progress here, just chasing my tail. Here's how the array of subnet IDs is created in the infrastructure stack:
Copy code
privSubnetIds := make([]pulumi.StringInput, numOfAZs)
		for idx := 0; idx < numOfAZs; idx++ {
			subnetAddr := (idx * 32) + 16
			subnetCidrBlock := fmt.Sprintf("%s%d.0/22", netAddrMap[awsRegion], subnetAddr)
			subnet, err := ec2.NewSubnet(ctx, fmt.Sprintf("priv-subnet-%d", idx), &ec2.SubnetArgs{
				VpcId:               vpc.ID(),
				AvailabilityZone:    pulumi.String(azNames[idx]),
				CidrBlock:           pulumi.String(subnetCidrBlock),
				MapPublicIpOnLaunch: pulumi.Bool(false),
				Tags: pulumi.StringMap{
					"Name": pulumi.String(fmt.Sprintf("%s-priv-subnet-%d", baseName, idx)),
					k8sTag: pulumi.String("shared"),
				},
			})
			if err != nil {
				log.Printf("error creating private subnet: %s", err.Error())
			}
			privSubnetIds[idx] = subnet.ID()
		}
		ctx.Export("privSubnetIds", pulumi.StringArray(privSubnetIds))
Should I be a) using a different type for
privSubnetIds
, b) using a different
pulumi.<type>
function in the Export, c) both a and b, or d) something else entirely? Or is the problem in how I am bringing the value(s) into the second stack?
@lemon-agent-27707 @billowy-army-68599 Any thoughts on the above update?
b
@salmon-account-74572 I personally export the subnets as an IDArrayOutput: https://github.com/jaxxstorm/pulumi-aws-vpc/blob/go/go/main.go#L27 https://github.com/jaxxstorm/pulumi-aws-vpc/blob/go/go/main.go#L129 and then pass them as a stackref and you can wrap as a `pulumi.StringArrayOutput`: https://github.com/jaxxstorm/iac-in-go/blob/master/eks/main.go#L142
l
Will take a look this morning. I believe that the casting the result of
GetOutput
to pulumi.StringArrayOutput is unsafe and can fail if the value is
nil
.
I will give it a try locally, but it probably needs to use an apply that checks for nil values similar to what we do for string output conversion: https://github.com/pulumi/pulumi/blob/master/sdk/go/pulumi/stack_reference.go#L25-L33
👍 1
s
@billowy-army-68599 I've tried your approach (switching the original array in my infrastructure stack to
[]pulumi.IDOutput
, and then using your
idOutputArrayToIDArrayOutput
function when exporting the array; in the stack reference defining it as a
StringArrayOutput
). The problem is when I go to reference a specific element in the array, and Go reports that "it cannot index variable of type pulumi.StringArrayOutput".
b
ah, then you'll definitely need an apply
s
Got an example? The Pulumi "Programming Model" page that talks about Apply lacks examples for Go.
b
l
I'll send you something momentarily.
@salmon-account-74572 It's generally unsafe to handle stack references by trying to just wrap them with
pulumi.***(...)
You'll need to write the appropriate apply functions. Here's an example of something I put together. First program exports a
pulumi.StringArray
and the second one imports it, and manipulates it to get the first value.
Copy code
package main

import (
	"<http://github.com/pulumi/pulumi/sdk/v2/go/pulumi|github.com/pulumi/pulumi/sdk/v2/go/pulumi>"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		ctx.Export("ref", pulumi.StringArray{
			pulumi.String("foo"),
			pulumi.String("bar"),
		})
		return nil
	})
}
Copy code
package main

import (
	"<http://github.com/pulumi/pulumi/sdk/v2/go/pulumi|github.com/pulumi/pulumi/sdk/v2/go/pulumi>"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		ref, err := pulumi.NewStackReference(ctx, "EvanBoyle/ref1/dev", nil)
		if err != nil {
			return err
		}
		strarr := ref.GetOutput(pulumi.String("ref")).ApplyStringArray(func(out interface{}) []string {
			var res []string
			if out != nil {
				for _, v := range out.([]interface{}) {
					res = append(res, v.(string))
				}
			}
			return res
		})

		idx0 := strarr.ApplyString(func(a []string) string {
			var res string
			if len(a) > 0 {
				res = a[0]
			}
			return res
		})
		ctx.Export("idx0", idx0)
		return nil
	})

}
This could be modified to handle IDs as well by changing
ApplyStringArray
and
ApplyString
to
ApplyIDArray
and
ApplyID
.
b
would be good to get that into the pulumi examples somehow, I opened this and will try take care of it: https://github.com/pulumi/examples/issues/748
s
@lemon-agent-27707 OK, I can understand what is happening with `ApplyStringArray`; we're basically iterating over the array from the stack reference. Two questions: 1. Why is
strarr
still listed as type StringArrayOutput, seems like it should just be StringArray? 2. Should I not just be able to do
strarr[0]
, why the need for the function to get out the indexed value?
l
1. Why is 
strarr
 still listed as type StringArrayOutput, seems like it should just be StringArray?
GetOutput
will always return an
Output
, not a prompt value. Also
Apply
and it's many forms will always return outputs.
2. Should I not just be able to do 
strarr[0]
, why the need for the function to get out the indexed value? 
The value that pulumi sees in the apply is of type
[]interface{}
. So we must cast to the appropriate type. The reason for this is that
GetOutput
is intended to be a generic method that supports all types. We should improve the experience here by offering common helpers for stackrefs like
GetStringArrayOutput
and
GetIDArrayOutput