Using Pulumi Outputs as a string input is breaking...
# typescript
a
Using Pulumi Outputs as a string input is breaking my brain... It should be simple and I've tried using concat, interpolate and .apply but nothing seems to allow me to access the string of the output. How do I take an output of a vnet id and pass it as a string to call another class? Here's my code
Copy code
import * as pulumi from "@pulumi/pulumi";
import { ComponentResource, Input, Output } from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
import * as azure from "@pulumi/azure";
import { roleAssignment } from "../roleAssignment/roleAssignment";

let config= new pulumi.Config('env')

export class virtualNetwork {
    constructor(name: string) {
        const dpc_vnet_aue_001 = new azure.network.VirtualNetwork(name+"-aue-"+config.require('index'), {
            addressSpaces:
                config.requireObject(name+'-vnetrange'),
            location: config.require('location'),
            name: name+"-"+config.require('envid')+"-aue-"+config.require('index'),
            resourceGroupName: "dpc-spi-networking-"+config.require('envid')+"-rg-aue-"+config.require('index'),
        }, {
            protect: true,
        });
        const vnet_id = dpc_vnet_aue_001.id
        const aadplatforms_networkContributor = new roleAssignment(name+"aadplatforms_networkContributor", {
            principleId: config.require('aadplatforms'),
            principleType: "Group",
            roleDefinition: config.require('networkContributor'),
            //scope: pulumi.concat `${dpc_vnet_aue_001.id}`,
            //scope: vnet_id,
            scope: dpc_vnet_aue_001.id
        }
        )
    }   
}
I've commented some previous attempts but vscode just tells me that what I'm passing isn't a string.
l
By the looks of it, you're using it correctly. Most likely, the problem is that your own constructor (
roleAssignment
) is typing is as a string instead of an
Output<string>
.
There is a bug* in the documentation that removes the generic
Output<string>
from all
string
types, and my guess is that you're picking up on that, and defining the
scope
value to have type
string
. But it needs to be
Output<string>
. (*: Pulumi states "it's correct by design" but it confuses all newcomers, so I call that a bug.)
a
Great. So I imported Output and I made the type Output<string> in my roleAssignment class. I'm getting somewhere. I'll let you know how I go... Thanks.
Solution: The solution was to change the receiving variable type for scope in my roleAssignment class to type Input<string>. To use this variable type you must import { Input } from. "@pulumi/pulumi"; Once this is done it sets up a dependency between the output value from the Vnet id and the input to the roleAssignment class. This essentially makes pulumi wait until it has a value for the input before it calls the dependency. You can achieve something similar by setting a variable by using the apply function. This code snippet prints the value as a pulumi warning then sets a variable that when you reference it pulumi will wait till the apply has run so you have a value in that variable.
Copy code
pulumi.output(args.scope).apply(v => {
            pulumi.log.warn(v)
        });
         const vnetId = pulumi.output(args.scope).apply(v => {
            return `${v}`
        })
The apply function makes pulumi wait until the Output variable has a value before it executes the apply on it. This means your code will pause and wait for this to occur when you attempt to reference the variable vnetId. It's all about parallelism and making pulumi wait until an Output object has a value before you can reference it. Thanks @steep-sunset-89396 for explaining this to me. I hope my poor and slightly uninformed explanation helps anyone searching for this.
l
You shouldn't need that apply in that case, since it's not transforming the value. Pulumi will wait on values when it's constructing new resources. That is, your own code that doesn't use the vnet id doesn't have to wait: only the Pulumi code that does use it has to wait, and it already does that. You don't have to make the Pulumi code wait.
If your code needs to use the vnet id, then you would have to wait.. but in that case, your code would need to be inside the apply. You can't run the apply then do stuff afterwards. The "afterwards" code runs before the code inside the apply.
s
@little-cartoon-10569 What isn't shown in the snippet above was the ComponentResource and the interface. I wanted to demonstrate how an Input can take an Output as a value. but also an Input can receive a string as a value.
@able-engineer-79880 clearly understood how to pass outputs through the interface and the connection Input/Output wasn't so clear. Same with the apply() as a way to "reveal" the value at the Output (but not as a way to extract the value).
👍 1
And finally, showing pulumi.output() was also a good exercise to convert the Input and demonstrate how to use the apply() in his code if needed.
So it was much more about common patterns than what was strictly required to actually get the code working.
👍 1
a
Yep. The 'solution' was setting the incoming type to Input<string>, The rest of the code snippets were just examples that helped me understand it and could be useful for the uninitiated.
👍 1