Is there a way (especially in Go) to export an arr...
# general
b
Is there a way (especially in Go) to export an array of values (say array of strings) from one stack and import it into another without hating your decision? Both the casting to
StringArrayOutput
in and of itself is difficult, and working with
StringArrayOutput
in the code (e.g. if you want to iterate over it to create something for each element) is just very very painful.
l
Would it be easier to export it as a key-value map? I have no idea about the golang-related complexities. It's not hard either way in TS.
b
This is my Go code to do the first part of the conversion:
Copy code
func GetStringArrayOutput(ref *pulumi.StackReference, key string) pulumi.StringArrayOutput {
	output := ref.GetOutput(pulumi.String(key))
	return output.ApplyT(func(input interface{}) []string {
		vals := make([]string, len(input.([]interface{})))
		for idx, val := range input.([]interface{}) {
			vals[idx] = val.(string)
		}
		return vals
	}).(pulumi.StringArrayOutput)
}
I think a map would actually be even worse šŸ™‚
@little-cartoon-10569 how are you iterating over the output? Say I wanted to create a new resource per item in the output, what do you do? To actually iterate, youā€™d need to do an
Apply
, but then I try and avoid creating resources in
Apply
. The other option is to call the
Index(i)
method, but thereā€™s no way to know the length (unless you also export that). This is the kind of stuff I mean
l
Creating resources based on results of Outputs is something I always avoid. And unfortunately, exporting the length doesn't help the issue, since the exported value is also in an Output.
You can either move the values from stack references to config (ick), or redesign something. It's (almost?) always possible. You really, really want to avoid mistakes like awsx.ec2's VPC subnets issue. It's awful.
But it is an example of the problem you're talking about. You configure the number of subnets as a parameter, it creates a variable number of subnets, and as a result, you can only access your subnets inside an Output. It's a really good reason to not use awsx.
b
Ah yes, youā€™re right on the length in - I tried to do exactly that, ran into that issue, and gave up šŸ˜„
Yeah, we donā€™t use
awsx
(because itā€™s not available for Go as the main reason šŸ™‚ ), but what you said is exactly the type of thing I am thinking about. An example is I want to create some R53 records in my infrastructure stack, and then I want some downstream stack to be able to leverage those and create something based on them (e.g. a cert or something). Itā€™s hard because of these types of issues, and usually requires a lot of gymnastics in order to avoid.
p
can you not simply work with an array of elements? Iā€™m a total newbie, so iā€™m probably misunderstanding your question, but this is how iā€™m making a firewall per linode node:
Copy code
func Firewall(ctx *pulumi.Context, instances []*linode.Instance, region string) (*linode.Firewall, error) {
	var linodes pulumi.IntArray
	for _, instance := range instances {
		instanceId := instance.ID().ToStringOutput().ApplyT(parseString()).(pulumi.IntInput)
		linodes = append(linodes, instanceId)
	}
	var wall, err = linode.NewFirewall(ctx, "Firewall", &linode.FirewallArgs{
		Label: pulumi.String("Firewall"),
		Tags: pulumi.StringArray{
			pulumi.String("test"),
		},
		InboundPolicy:  pulumi.String("DROP"),
		OutboundPolicy: pulumi.String("DROP"),
		Linodes: linodes,
	})
...
b
@proud-angle-89904 itā€™s a good question. The issue is that itā€™s exported from one stack (i.e.
ctx.Export("my-key", someStringArrayOutput)
And when you import it on the other side, itā€™ll be a
pulumi.AnyOutput
and you have to do some casting magic to get it to be
pulumi.StringArrayOutput
In your example, your
instances
array is actually a real array/slice, so you can iterate over it. And even your
linodes
is a
[]<http://pulumi.Int|pulumi.Int>
(just typedefā€™ed to
IntArray
).
l
If feasible, put the R53 and dependent resources in the same project. Maybe even in the same ComponentResource?
Sidestep the issue.
A new CertifiedARecord component resource sounds perfect šŸ™‚
Then you'll need a CertifiedCNameRecord... šŸ™‚
b
Right, but that only really works if itā€™s in the same project (i.e. in the same stack), no? In this case, thatā€™s not really feasible - I need to create something once and reference many times.
l
Not necessarily. You can export your ReallyImportantRecordId (not an array: they're important, so you must know all them in advance, so you can export them all individually), then in the other project, you can use
Record.get()
inside your component resource's constructor. Then you'll have a real (but read-only) instance of the Record.
p
huh, til what the ctx.Export is for
b
@little-cartoon-10569 thatā€™s fair, if you know them all in advance šŸ™‚ In my case, I donā€™t, they come from the config. Anyway, I do get what youā€™re saying, which boils down to ā€œthis is going to be painful unless you avoid this problem altogetherā€, which is very fair.