I'm continually struggling with Outputs and Inputs...
# general
p
I'm continually struggling with Outputs and Inputs, which I think may be somewhat to do with being new to Golang, and typed languages in general. I used to write in perl, which is polymorphic, and when I use the ApplyT functions I seem to end up with a lot of type errors and panics which I don't understand. I'm going to explain these, with code examples in a thread and hopefully someone can demystify this for me.
💯 1
I have some code, which apparently I wrote, or at least copy from somewhere which works quite happily and looks like so:
Copy code
// because the node sg is wrapped up in some weird output nonsense we need to free it
nsg := cluster.NodeSecurityGroup.ApplyT(func(nodesg *ec2.SecurityGroup) pulumi.StringOutput {
	return nodesg.ID().ToStringOutput()
}).ApplyT(func(id interface{}) string {
	return id.(string)
}).(pulumi.StringOutput)
cluster
is an EKS cluster created using eks.NewCluster what I think this code does is create a function called nodesg which takes a *ec2.SecurityGroup object as input and returns a pulumi.StringOutput object. That function returns the output of the ID() function fed into the ToStringOutput() function both of which are provided in the nodesg *ec2.SecurityGroup object which we were taking as an input. But then that seems to be nested with a second ApplyT which declares a function called id which takes an interface{} and returns a string, which I guess is taking the output of the nodesg function (which I thought was a pulumi.StringOutput, but I guess it's also an interface{}) and converting it to a string, which is then converted back to a pulumi.StringOutput but the last .() Am I right? Am I close? I'd appreciate any insight into what this code does as I really don't think I understand it.
I then tried to copy this in order to do much the same thing with the InstanceRole so I can add more permissions to it. The code:
Copy code
// extract the role from the cluster output
iRole := cluster.Core.ApplyT(func(irole *eks.CoreData) pulumi.StringOutput {
    return irole.InstanceRoles[0].Name
})
I've tried this, I've tried adding a second .ApplyT with the func(foo interface{}) string {... and I've tried having .(pulumi.StringOuput) after the last )
None have worked and most have given me the error:
Copy code
Diagnostics:
  pulumi:pulumi:Stack (EKS-EKS-test):
    panic: applier must have 1 input parameter assignable from eks.CoreData
    goroutine 1 [running]:
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.makeContextful({0x1110880|github.com/pulumi/pulumi/sdk/v3/go/pulumi.makeContextful({0x1110880>, 0x14d7718}, {0x164b750, 0x145f9e0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/types.go:340 +0x4a6
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyT(0xc0000d7490|github.com/pulumi/pulumi/sdk/v3/go/pulumi.(*OutputState).ApplyT(0xc0000d7490>, {0x1110880, 0x14d7718})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/types.go:419 +0x5d
    main.main.func1(0xc00037db80)
        /home/ubuntu/docker/EKS/pulumi/main.go:411 +0x32b3
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext>(0xc00037db80, 0x14d7720)
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:103 +0x199
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5>, {0x0, 0x0, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:84 +0x310
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0|github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0>, {0x0, 0x10d0680, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:41 +0x25
    main.main()
        /home/ubuntu/docker/EKS/pulumi/main.go:18 +0x27
    exit status 2
 
    error: an unhandled error occurred: program exited with non-zero exit code: 1
Which I must confess confuses me further, but maybe it wants me to have one of the Input parameters used in my function, which I'll try next.
If anyone has any helpful words of advice/explanation they will be gratefully received.
l
Hello @polite-napkin-90098, while not an expert in Go, I want to verify something on your approach of Pulumi code, based on this comment:
Copy code
// because the node sg is wrapped up in some weird output nonsense we need to free it
Question: do you expect to get a (free)
string
after using
ApplyT
callback which you would be able to use further in your application? The reason I’m asking this is that I have been bitten by this myself when I started using Pulumi. In an oversimplified way, you have to think as the language host (the runtime you use to write your infra code in, in your case Go) running your infra code, which talks to the Pulumi engine to instruct which resources need to be set up. By the time your code has run, none of your resources have been set up yet. The Pulumi engine takes the instructions, calculates a directed acyclic graph (DAG) and knows in which order it can set up these resources based on outputs of one resource being used as input to others. Think of an output as a bucket which will have a value in the future.
ApplyT
will invoke your call-back function at the time the value becomes available, but the result you return in your callback function, will be put again in an Output which you can pass around as inputs further in your code.
p
Thanks @limited-rainbow-51650 I am aware of the runtime nature of the ApplyT function and that it is providing a promise of a future value, i.e. the id of the security group in the working example and the name of the Role in the second non-working value. That's what I was referring to as 'nonsense' which I guess is somewhat uncharitable of me, but I may have been somewhat frustrated when I wrote that comment.
l
Q2 regarding the line below:
Copy code
nsg := cluster.NodeSecurityGroup.ApplyT(...
Where do you get
NodeSecurityGroup
from? I can’t find this as an output in the API docs of `Cluster`: • aws-classic: https://www.pulumi.com/registry/packages/aws/api-docs/eks/cluster/#outputs • aws-native: https://www.pulumi.com/registry/packages/aws-native/api-docs/eks/cluster/#outputs
b
I also struggle with golang but maybe this is relevant, it looks like the SecurityGroup type inherits from
pulumi.CustomResourceState
while the CoreDataOutput type inherits from
pulumi.OutputState
. Maybe I'm misunderstanding but given that
eks
is one of the combined providers, is one of those properties actually a Resource being forwarded from the inner component while the other is an Output?
It looks like your apply function parameter is trying to take in an element of type eks.CoreData when that property is actually eks.CoreDataOutput . Again, I may be misreading the code it being golang lol Disregard I think this comment is me misunderstanding the way generics currently look in golang
p
Maybe I should stop struggling with golang and switch to Typescript.
b
hahaha well hopefully we can figure this out without you having to do that. It's probably something silly
Hmm how about the fact that your
ApplyT
delegate returns a
stringOutput
? Shouldn't your delegate return a non-output type, since the
ApplyT
method signature is essentially
Output<Y> Apply<T>(Func<T, Y> delegate);
. I think your first working example has some excessive
ApplyT
calls
p
I'm currently trying to modify that function and get it to return something else, but
irole.InstanceRoles[0].Name
seems to be a pulumi.StringOutput, although I could always change that.
b
Yea it's weird to me that in your working example: 1. Your first apply turns a
string
into a
stringOutput
2. Your second apply turns in back into a
string
3. You turn the result back into a
stringOutput
Kinda confused by that snippet
l
Same here.
b
Checkout this example in the docs: the inner delegate returns a non output type, and the result is turned into an output type - essentially doing the same thing as your first working example with a single ApplyT call.
p
Yeah, I can't say it makes sense to me. I suppose I could try changing it, by way of further example this is how to get the kubeconfig, using a similar method:
Copy code
kubeconfig := cluster.Kubeconfig.ApplyT(func(kc interface{}) string {
			str, err :=json.Marshal(kc)
			if err != nil {
				panic(err)
			}
			return string(str)
		}).(pulumi.StringOutput)
I guess that's more straight forward with the ApplyT taking the interface kc and returning a string made by marshalling the json
b
Yea that is what I would expect that to look like.
p
I have something in my memory about it being because of the ID() function. I'll have a go at removing the second ApplyT in the other example, but I still don't understand the
panic: applier must have 1 input parameter assignable from eks.CoreData
error
l
Copy code
nsg := cluster.NodeSecurityGroup.ApplyT(func(nodesg *ec2.SecurityGroup) pulumi.StringOutput {
	return nodesg.ID()
}).(pulumi.StringOutput)
In my head, I would simplify the first example to this. Don’t know if this is valid Go+Pulumi code though.
b
The second example you are having trouble with a maybe a little trickier because it is an output object with a nested property that you want to access. Is this possible?
Copy code
// extract the role from the cluster output
iRole := cluster.Core.InstanceRoles.ApplyT(func(irole *whateverthistypeis) string {
    return irole[0].Name
}).(pulumi.StringOutput)
Or do the typings not permit you to access
InstanceRoles
without the apply? Again this is me having trouble reading golang type definitions lol
p
yeah that's what I was about to try. I'll let you know if it doesn't work
I tried that, it said that InstanceRoles has no function or property ApplyT
b
ah because it is not an output. But you are able to access it at all though? That seems odd. I would instead expect it to say that
Core has no function or property InstanceRoles
if
Core
was an output
p
Ok when trying to remove the second ApplyT in the first example I get the error:
/main.go:350:16: cannot use sg.CustomResourceState.ID() (type pulumi.IDOutput) as type pulumi.StringOutput in return argument
so I think the second ApplyT is turning the pulumi.IDOutput into a pulumi.StringOutput
b
share the snippet that gave you that error?
l
I guess that was the snippet I posted as simplification a few minutes ago.
p
Copy code
// because the cluster sg is wrapped up in some weird output nonsense we need to free it
sgid := cluster.NodeSecurityGroup.ApplyT(func(sg *ec2.SecurityGroup) pulumi.StringOutput {
       return sg.ID()
}).(pulumi.StringOutput)
l
Is this better?
Copy code
nsg := cluster.NodeSecurityGroup.ID().ApplyT(func(id interface{}) string {
	return id.(string)
}).(pulumi.StringOutput)
☝️ 1
p
With the commented code removed
b
Yea I'm still confused by that ^. Because your ApplyT delegate is still returning an output value. You shouldn't be needing to deal with outputs inside of your ApplyT delegate, that's the whole point of the delegate - you are accessing a future value when it is available
p
Copy code
Diagnostics:
  pulumi:pulumi:Stack (EKS-EKS-test):
    # EKS
    ./main.go:239:35: cluster.NodeSecurityGroup.ID undefined (type ec2.SecurityGroupOutput has no field or method ID)
    ./main.go:353:16: cannot use sg.CustomResourceState.ID() (type pulumi.IDOutput) as type string in return argument
I'll see if I can find the docs/article where I copied this code from, but I think it's only for ID() which is why it is strnage.
https://github.com/pulumi/pulumi/issues/4080 < I think this is relevant i.e "We can add
AnyOutput
to
StringOutput
or
IDOutput
to this list I believe as there's no easy way without applying another
applier func
to it"
https://githubhot.com/index.php/repo/pulumi/pulumi-eks/issues/644< here you can see my code offered as a solution to this problem
but this is all a Red Herring on the current issue, as eks.CoreData isn't giving us an IDOutput
b
Did you see that that issue references another issue, that references a PR that resolved that by supposedly adding some functions to make that easier? https://github.com/pulumi/pulumi/pull/6337
p
Yes, I did notice that but I haven't tried those functions yet.
I'll have a look at them now.
b
You're correct that the issue with the
CoreData
delegate is that it is an Output<CoreData> type that is then giving you an Output<string> inside the delegate so we need one the pulumi golang guys to go over how or what you're supposed to return from that delegate in order to unwrap the inner output
p
Yes, that sounds about right. I'll keep fiddling with it and see if I can find the right incantation in the meantime
b
Checkout this function: https://github.com/pulumi/pulumi-eks/blob/d599a1b1f3650dba4c3dc4f560080e95ce6fb5b1/sdk/go/eks/pulumiTypes.go#L946 Can you do:
Copy code
// extract the role from the cluster output
iRole := cluster.Core.InstanceRoles().ApplyT(func(irole []*iam.Role) string {
    return irole[0].Name
}).(pulumi.StringOutput)
p
Sorry, got distracted by boring things like meetings. I'll give that a whirl
That changes the error, first it complained that irole[0].Name was a pulmi.StringOutput and not a string so fixing the typing to:
Copy code
iRole := cluster.Core.InstanceRoles().ApplyT(func(irole []*iam.Role) pulumi.StringOutput{
  return irole[0].Name
})
I now get
panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
but I was expecting it to complain that InstanceRoles didn't have .ApplyT so that's new, and potentially useful
b
Is the role something you are creating or are you allowing the cluster to create it?
p
It is the one created by the EKS package, or maybe by the AWS api.
I did try creating a role and passing that to the eks.NewCluster, but I never seemed to get the right bundle of permissions and my nodes never managed to join the cluster.
I found out why I though I would get an error like:
cluster.Core.InstanceRoles.ApplyT undefined (type func() iam.RoleArrayOutput has no field or method ApplyT)
as that is what happens when when you leave the brackets out of
cluster.Core.InstanceRoles.ApplyT
and not
cluster.Core.InstanceRoles().ApplyT
b
yes,
CoreDataOutput
type has no properties. It has functions only, that are used to access the properties of
CoreData
.
p
that makes sense
b
After you call
InstanceRoles()
you just have a standard
iam.RoleArrayOutput
that you should be able to use normally as you would use it from the iam provider. For instance you could use this function to get a specific index of the array. So maybe
cluster.core.InstanceRoles().Index(0).ApplyT(func(irole *iam.Role) string { return irole.Name });
or something like that.
p
ah yes, I was looking for that Index(0) function, thanks!
🙌 1
although I need to make the 0 a
pulumi.IntInput
b
you should be able to cast a constant to an input if it isn't inferred automatically. Since input types are just designed to accept either runtime values or output values
p
I don't seem to be able to make that happen. I've tried:
Copy code
var index pulumi.IntInput = pulumi.IntInput(0)
iRole := cluster.Core.InstanceRoles().Index(index).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
      return irole.Name
})
and some variations but I mostly get errors like
Copy code
pulumi:pulumi:Stack (EKS-EKS-test):
    # EKS
    ./main.go:411:46: cannot convert 0 (type int) to type pulumi.IntInput:
        int does not implement pulumi.IntInput (missing ElementType method)
Which is the kind of thing which makes me long for polymorphism
Copy code
iRole := cluster.Core.InstanceRoles().Index(pulumi.IntInput(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
   return irole.Name
})
is a simpler form, but it gives the same error.
b
you're trying to use a type as a function I think... based on your previous samples doesn't casting in go look like
0.(pulumi.IntInput)
sorry you were closer, pulumi docs look like it is actually
<http://pulumi.Int|pulumi.Int>(0)
that you want
p
yeah I tried that but it results in
Copy code
# EKS
    ./main.go:411:49: cannot call non-function 0 (type float64)
    ./main.go:411:50: type pulumi.IntInput is not an expression
Yeah so I also tried that, maybe getting to the conclusion the same time as you but that results in
b
look here: https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#lifting A little down the page there is:
Copy code
cert.DomainValidationOptions.Index(<http://pulumi.Int|pulumi.Int>(0)).ResourceRecordValue().Elem(),
p
Copy code
Diagnostics:
  pulumi:pulumi:Stack (EKS-EKS-test):
    error: an unhandled error occurred: program exited with non-zero exit code: 1

    panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
    goroutine 1 [running]:
    <http://github.com/pulumi/pulumi-eks/sdk/go/eks.CoreDataOutput.InstanceRoles({0xc00024c1e0})|github.com/pulumi/pulumi-eks/sdk/go/eks.CoreDataOutput.InstanceRoles({0xc00024c1e0})>
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi-eks/sdk@v0.36.0/go/eks/pulumiTypes.go:947 +0x54
    main.main.func1(0xc0000fa140)
        /home/ubuntu/docker/EKS/pulumi/main.go:411 +0x3265
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext>(0xc0000fa140, 0x14d6720)
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:103 +0x199
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5>, {0x0, 0x0, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:84 +0x310
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0|github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0>, {0x0, 0x10cf680, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:41 +0x25
    main.main()
        /home/ubuntu/docker/EKS/pulumi/main.go:18 +0x27
    exit status 2
But somehow seems closer
So maybe this?
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).Name();
I'm seeing a lot of
Property()
for things I think are properties in the golang sdk lol
p
That gives:
./main.go:411:61: cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).Name undefined (type iam.RoleOutput has no field or method Name)
I think we need the ApplyT in there too.
b
But the
ApplyT
doesn't change the fact that Name is a
pulumi.StringOutput
inside the delegate so that isn't what we want
We shouldn't have outputs inside our apply delegate.
What does calling
.Elem()
on the result of
.Index(<http://pulumi.Int|pulumi.Int>(0))
give you for a type?
p
I tried:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).Elem().ApplyT(func(irole *iam.Role) pulumi.StringOutput{
    return irole.Name
})
but that gives:
Copy code
error: an unhandled error occurred: program exited with non-zero exit code: 2

    # EKS
    ./main.go:411:61: cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).Elem undefined (type iam.RoleOutput has no field or method Elem)
b
@lemon-agent-27707 we need some golang expertise. It's something silly I'm missing. We've got a type of
eks.Cluster
We're trying to get the first element of the instance roles array on the
eks.Cluster
. Using
cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0))
gets us the first element of the
RoleArrayOutput
returned by
InstanceRoles()
. That first element is of type
RoleOutput
. How do you get the
.Name
property off of this element?
👍 1
p
Thanks very much for all the help so far @bored-oyster-3147. I'm about to head home for the evening but will pick this up tomorrow.
b
Good luck. Sorry I suck at golang! lol
l
Looks like ya'll have tried lots of things. What was the issue with doing something like:
Copy code
cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(...
Shouldn't need the
Elem
I don't think
b
Yea I realized after that golang has PtrOutput types and that is what that is for. The issue with the apply was that the
.Name
property was still a
pulumi.StringOutput
inside the apply
l
It makes sense that it would be an output.
Role
is a resource.
I don't have an example handy. I wonder if you could do one apply that returns the
Name
output, and then a second apply on that result to manipulate the underlying value.
something like:
Copy code
name := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(...

nameResult := name.Apply(...
b
Does it make sense that it is an output? Usually the resource itself isn't also an output. I would expect that it be
Resource.PropertyOutput
so you could
Role.Name.Apply(...)
but in this case it is
ResourceOutput
so you have to
Role.Apply(...)
which is very weird when he just wants to get the name and pass it around, he doesn't even want to manipulate the name. If it was just a resource he could just
var roleName = Role.Name;
and he would be fine, no apply necessary. But since the role itself is an output, that isn't possible since
.Name
isn't accessible. @polite-napkin-90098 did you try doing:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput {
  return irole[0].Name
});
p
I'll get some fresh tea and give it a go.
1
So if I use it as you wrote it, I get an error about *iam.Role not being indexable, due to the [0] after irole. If I drop that I get the
panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
error.
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
                        return irole.Name
})
I've tried a few more variations, all with similar results to the above. Unless anyone knows how to actually do this I think my best path is to either try again in a different language, or maybe drop pulumi for something else like Terraform
b
Ok the square brackets were a typo on my part with the given example. The error above hopefully Evan can weigh on because that is the real issue, given that the above is what he was thinking would work
👍 1
p
So I installed the CoC plugin for vim and now have VSCode style completion in golang. This then led me to find that I can do this:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
          return irole.Name.ToStringOutput
})
Which gives the error:
./main.go:412:21: cannot use irole.Name.ToStringOutput (type func() pulumi.StringOutput) as type pulumi.StringOutput in return argument
which seems to be progress
Hmm so I tried:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
                        return irole.Name.ToStringOutput()
                }).ApplyT(func(iro interface{}) string {
                        return iro.(string)
                }).(pulumi.StringOutput)
Which is similar to the Security Group example I posted a couple of days ago in this thread. Unfortunately that errors with:
Copy code
Diagnostics:
  pulumi:pulumi:Stack (EKS-EKS-test):
    panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
    goroutine 1 [running]:
    <http://github.com/pulumi/pulumi-eks/sdk/go/eks.CoreDataOutput.InstanceRoles({0xc0002121e0})|github.com/pulumi/pulumi-eks/sdk/go/eks.CoreDataOutput.InstanceRoles({0xc0002121e0})>
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi-eks/sdk@v0.36.0/go/eks/pulumiTypes.go:947 +0x54
    main.main.func1(0xc0004b6000)
        /home/ubuntu/docker/EKS/pulumi/main.go:411 +0x32a5
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunWithContext>(0xc0004b6000, 0x14d6af0)
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:103 +0x199
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5|github.com/pulumi/pulumi/sdk/v3/go/pulumi.RunErr(0x43efc5>, {0x0, 0x0, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:84 +0x310
    <http://github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0|github.com/pulumi/pulumi/sdk/v3/go/pulumi.Run(0x0>, {0x0, 0x10cf720, 0xc0000001a0})
        /home/ubuntu/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.24.1/go/pulumi/run.go:41 +0x25
    main.main()
        /home/ubuntu/docker/EKS/pulumi/main.go:18 +0x27
    exit status 2
So there's still some kind of type confusion going on 😬
b
Does just your first .ApplyT work? why do you need the second one. Presumably you already have a
StringOutput
that you can pass around after the first. I mean this:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput {
    return irole.Name.ToStringOutput()
})
the fact that you have to
.ToStringOutput()
it at all implies that it is not in fact a string output inside the apply function so why the heck doesn't this work:
Copy code
iRole := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) string {
    return irole.Name
}).(pulumi.StringOutput)
I'm honestly really confused about this
p
I thought I had tried your first example before I added in the second ApplyT, but maybe I missed the () from the ToStringOutput() and got some other error. I get the same error
panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
for your first code block.
I think I've tried the other one too, gimme a sec...
yeah both of those give the same panic error.
Copy code
func (o CoreDataOutput) InstanceRoles() iam.RoleArrayOutput {
        return o.ApplyT(func(v CoreData) []*iam.Role { return v.InstanceRoles }).(iam.RoleArrayOutput)
}
This is the function in
go/eks/pulumiTypes.go:947
which is barfing. I guess the Index() is after a pulumi.AnyOutput and not a iam.RoleArrayOutput
yeah and using my funky new vim plugin IntancesRoles() doesn't want to complete with .Index()
Copy code
iRole := cluster.Core.InstanceRoles().ApplyT(func(irole []*iam.Role) pulumi.StringOutput{
                        return irole[0].Name
                }).(pulumi.StringOutput)
This also gives the:
panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
I'm off to drink beer and enjoy my weekend. I'll pick this up on Mon
🍻 1
Well I've tried a few more convolutions of this this morning, but I still can't make it work. I'm going to try typescript instead.
b
I'm sorry I can't be of more help. I'm frustrated by proxy, to be honest lol. Certainly doesn’t improve my opinion of golang
p
No worries, thanks for all your help. I too am liking golang significantly less after this. We'll see if typescript is less mind bending.
l
@polite-napkin-90098 sorry you're running into so many issues here. It looks like the last few issues you ran into might be related to a known bug working with
StringOutput
There is a workaround here that you might be able to try: https://github.com/pulumi/pulumi/issues/6073#issuecomment-809669645
☝️ 1
👀 2
p
Thanks Evan I'll take a look at that. I've found I tend to be quite good at finding bugs in things, which is a curse and a blessing 😉
🥲 1
I had tried something similar to this a few days ago https://pulumi-community.slack.com/archives/C84L4E3N1/p1649445617086939?thread_ts=1649258358.357719&amp;cid=C84L4E3N1 and following the example Evan linked I've tried:
Copy code
// extract the role from the cluster output
                iRol, err := cluster.Core.InstanceRoles().ApplyT(func(irole []*iam.Role) pulumi.StringOutput{
                        return irole[0].Name.ToStringOutput()
                }).(pulumi.AnyOutput), nil
                if err != nil {
                        return err
                }
                iRole, err := iRol.ApplyT(func(iro interface{}) string {
                        return iro.(string)
                }).(pulumi.StringOutput), nil
                if err != nil {
                        return err
                }
But both of them give the
panic: interface conversion: pulumi.Output is pulumi.AnyOutput, not iam.RoleArrayOutput
which happens in the cluster.Core.InstanceRoles().ApplyT line. Perhaps I need to use the
Index(<http://pulumi.Int|pulumi.Int>(0))
and only pass the first role (there is only one in my case) into the ApplyT and then extract the pulumi.String from the pulumi.AnyOutput
Copy code
iRol, err := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
                        return irole.Name.ToStringOutput()
                }).(pulumi.AnyOutput), nil
                if err != nil {
                        return err
                }
                iRole, err := iRol.ApplyT(func(iro interface{}) string {
                        return iro.(string)
                }).(pulumi.StringOutput), nil
                if err != nil {
                        return err
                }
This gives the same error
Copy code
iRol, err := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
                        return irole.Name
                }).(pulumi.AnyOutput), nil
Also gives the interface conversion panic, and
Copy code
iRol, err := cluster.Core.InstanceRoles().Index(<http://pulumi.Int|pulumi.Int>(0)).ApplyT(func(irole *iam.Role) pulumi.StringOutput{
                        return pulumi.String(irole.Name).ToStringOutput()
                }).(pulumi.AnyOutput), nil
gives
./main.go:412:24: cannot convert irole.Name (type pulumi.StringOutput) to type pulumi.String
which I guess makes sense. and proves that irole.Name is a pulumi.StringOutput
But this is all making me think that golang is the wrong language for pulumi
I've tried some more fiddling moving the ApplyT to earlier so it returns the CoreData object from the cluster and then get the Role Array inside that, but
Copy code
iRol, err := cluster.Core.ApplyT(func(irole *eks.CoreData) pulumi.StringOutput{
                        return irole.InstanceRoles[0].Name
                }), nil
or similar functions which return the []*iam.Role or just the zeroth *iam.Role result in
panic: applier must have 1 input parameter assignable from eks.CoreData
which is another error I'm struggling to understand and google just leads me to https://github.com/pulumi/pulumi-azure/issues/530 which doesn't help me much.
For the sake of closure. I have switched to using Typescript. I haven't quite got to the point where my cluster is working with PVC provisioned from EFS, but it is certainly much less fiddly to write.
b
I'm glad you found something that works for you. Shame it was such a pain! I'm sure you experience with the TS sdk will be smoother
p
Maybe I should have researched the languages available some more before jumping in. But, imho, the best way to learn and or decide if you like a language is to try using it for something real. As a perl/csh/bash programmer all that mucking about with types was far too mind-bending for me. 😉
b
Ha well even as a primarily dotnet programmer I still havent completely wrapped my head around go syntax and typing. The lack of true generic support means things get weird quick.