pulumipulumi-python

Pulum DigitalOcean: use outputs


I want to create some servers on DigitalOcean using Pulumi. I have the following code:

for i in range(0, amount):
    name = f"droplet-{i+1}"

    droplet = digitalocean.Droplet(
        name,
        image=_image,
        region=_region,
        size=_size,
    )
    pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)

This is correctly outputting the IP address of the servers on the console.

However I would like to use the IP addresses elsewhere in my Python script. Therefor I had added the droplets to a list as follows:

droplets = []

for i in range(0, amount):
    name = f"droplet-{i+1}"

    droplet = digitalocean.Droplet(
        name,
        image=_image,
        region=_region,
        size=_size,
    )
    pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)
    droplets.append(droplet)

to then loop over the droplets as follows:

for droplet in droplets:
    print(droplet.ipv4_address)

In the Pulumi output, I see the following:

Diagnostics:
  pulumi:pulumi:Stack (Pulumi_DigitalOcean-dev):
    <pulumi.output.Output object at 0x105086b50>
    <pulumi.output.Output object at 0x1050a5ac0>

I realize that while the droplets are still being created, the IP address is unknown but I'm adding the droplets to the list after the creation.

Is there a way to know the IP addresses at some point so it can be used elsewhere in the Python script.


Solution

  • The short answer is that because these values are Outputs, if you want the strings, you'll need to use .apply:

    https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#apply

    To access the raw value of an output and transform that value into a new value, use apply. This method accepts a callback that will be invoked with the raw value, once that value is available.

    You can print these IPs by iterating over the list and calling the apply method on the ipv4_address output value:

    ...
    pulumi.export(f"droplet-ip-{i+1}", droplet.ipv4_address)
    droplets.append(droplet)
    ...
    
    for droplet in droplets:
        droplet.ipv4_address.apply(lambda addr: print(addr))
    
    $ pulumi up
    ...
    
    Diagnostics:
      pulumi:pulumi:Stack (so-71888481-dev):
        143.110.157.64
        137.184.92.205
     
    Outputs:
        droplet-ip-1: "137.184.92.205"
        droplet-ip-2: "143.110.157.64"
    

    Depending on how you plan to use these strings in your program, this particular may may not be perfect, but in general, if you want the unwrapped value of pulumi.Output, you'll need to use .apply().

    The pulumi.Output.all() also comes in handy if you want to wait for several output values to resolve before using them:

    https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#all

    If you have multiple outputs and need to join them, the all function acts like an apply over many resources. This function joins over an entire list of outputs. It waits for all of them to become available and then provides them to the supplied callback.

    Hope that helps!