1. Docs
  2. Pulumi IaC
  3. Concepts
  4. Inputs & outputs
  5. Accessing single outputs with Apply

Accessing single outputs with Apply

    Outputs are asynchronous, meaning their actual plain values are not immediately available. Their values will only become available once the resource has finished provisioning. The asynchronous nature of Outputs is also why, when certain operations such as pulumi preview runs, the outputs for a new resource do not yet have any possible values. As such, there are limitations on the ways in which you can retrieve and interact with these values.

    To demonstrate, let’s say you have the following simple program that creates an AWSX VPC resource in AWS. In this program, you want to view all of the properties of this resource, so you have added a print/log statement to print the vpc variable.

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const awsx = require("@pulumi/awsx");
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    console.log(vpc);
    
    import * as pulumi from "@pulumi/pulumi";
    import * as awsx from "@pulumi/awsx";
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    console.log(vpc);
    
    import pulumi
    import pulumi_awsx as awsx
    
    vpc = awsx.ec2.Vpc("vpc")
    
    print(vpc)
    
    package main
    
    import (
        "fmt"
    	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ec2"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    
    		vpc, err := ec2.NewVpc(ctx, "vpc", nil)
    		if err != nil {
    			return err
    		}
    
            fmt.Println(vpc)
    
    		return nil
    	})
    }
    
    using Pulumi;
    using System.Collections.Generic;
    using Pulumi.Awsx.Ec2;
    
    return await Deployment.RunAsync(() =>
    {
        var vpc = new Vpc("vpc");
    
        Console.WriteLine(vpc);
    
    });
    
    package myproject;
    
    import com.pulumi.Pulumi;
    import com.pulumi.awsx.ec2.Vpc;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
    
                var vpc = new Vpc("vpc");
    
                System.out.println(vpc);
    
            });
        }
    }
    
    This example is not applicable in YAML.
    

    However, deploying this program will show CLI output similar to the following:

    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-js-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
        ...
        ...
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-js-dev):
        <ref *1> Vpc {
              __pulumiResource: true,
              __pulumiType: 'awsx:ec2:Vpc',
              ...
              ...
              vpc: OutputImpl {
                __pulumiOutput: true,
                resources: [Function (anonymous)],
                allResources: [Function (anonymous)],
                isKnown: Promise { <pending> },
                ...
                ...
              },
              ...
            }
    Resources:
        + 34 created
    
    Duration: 2m17s
    
    You can see an example of the complete Diagnostics CLI output in this gist.
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-ts-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
        ...
        ...
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-ts-dev):
        <ref *1> Vpc {
              __pulumiResource: true,
              __pulumiType: 'awsx:ec2:Vpc',
              ...
              ...
              vpc: OutputImpl {
                __pulumiOutput: true,
                resources: [Function (anonymous)],
                allResources: [Function (anonymous)],
                isKnown: Promise { <pending> },
                ...
                ...
              },
              ...
            }
    Resources:
        + 34 created
    
    Duration: 2m17s
    
    You can see an example of the complete Diagnostics output in this gist.
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-py-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
        ...
        ...
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-py-dev):
        <pulumi_awsx.ec2.vpc.Vpc object at 0x7f77ac256130>
    
    Resources:
        + 34 created
    
    Duration: 2m17s
    
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-go-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
        ...
        ...
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-go-dev):
        &{{{} {{0 0} 0 0 {{} 0} {{} 0}} {0xc000196e00} {0xc000196d90} map[] map[] <nil>   [] vpc [] true} {0xc0001961c0} {0xc000196230} {0xc0001962a0} {0xc000196460} {0xc0001964d0} {0xc000196690} {0xc000196700} {0xc0001967e0} {0xc000196850} {0xc0001968c0} {0xc000196930} {0xc000196a10} {0xc000196a80} {0xc000196b60}}
    
    Resources:
        + 34 created
    
    Duration: 3m7s
    
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-csharp-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
        ...
        ...
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-csharp-dev):
        Pulumi.Awsx.Ec2.Vpc
    
    Resources:
        34 created
    
    Duration: 3m7s
    
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-java-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
    ...
    ...
    
    # Nothing is printed
    
    Resources:
        + 34 created
    
    Duration: 2m17s
    
    This example is not applicable in YAML.
    

    As shown above, using this method will not provide a JSON representation of the VPC resource complete with its properties and associated property values. This is because, when it comes to Pulumi resource classes, there is no way to output this kind of JSON representation for a resource.

    Ultimately, if you want to view the properties of a resource, you will need to access them at the individual property level. The rest of this guide will demonstrate how to access and interact with a single property using apply apply Apply Apply .

    The apply method is great for when you need to access single values. However, if you need to access multiple output values across multiple resources, you will need to use Pulumi’s all method instead.

    Accessing single output values

    Let’s say you want to print the ID of the VPC you’ve created. Given that this is an individual resouce property and not the entire resource itself, you might try logging the value like normal:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const awsx = require("@pulumi/awsx");
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    console.log(vpc.vpcId);
    
    import * as pulumi from "@pulumi/pulumi";
    import * as awsx from "@pulumi/awsx";
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    console.log(vpc.vpcId);
    
    import pulumi
    import pulumi_awsx as awsx
    
    vpc = awsx.ec2.Vpc("vpc")
    
    print(vpc.vpc_id)
    
    package main
    
    import (
        "fmt"
    	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ec2"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    
    		vpc, err := ec2.NewVpc(ctx, "vpc", nil)
    		if err != nil {
    			return err
    		}
    
            fmt.Println(vpc.VpcId)
    
    		return nil
    	})
    }
    
    using Pulumi;
    using System.Collections.Generic;
    using Pulumi.Awsx.Ec2;
    
    return await Deployment.RunAsync(() =>
    {
        var vpc = new Vpc("vpc");
    
        Console.WriteLine(vpc.VpcId);
    
    });
    
    package myproject;
    
    import com.pulumi.Pulumi;
    import com.pulumi.awsx.ec2.Vpc;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
    
                var vpc = new Vpc("vpc");
    
                System.out.println(vpc.vpcId());
    
            });
        }
    }
    

    However, if you update the program as shown above and run pulumi up, you will still not receive the value you are looking for as shown in the following CLI output:

    # Example CLI output (truncated)
    Diagnostics:
      pulumi:pulumi:Stack (aws-js-dev):
        OutputImpl {
          __pulumiOutput: true,
          resources: [Function (anonymous)],
          allResources: [Function (anonymous)],
          isKnown: Promise { <pending> },
          isSecret: Promise { <pending> },
          promise: [Function (anonymous)],
          toString: [Function (anonymous)],
          toJSON: [Function (anonymous)]
        }
    
    # Example CLI output (truncated)
    Diagnostics:
      pulumi:pulumi:Stack (aws-js-dev):
        OutputImpl {
          __pulumiOutput: true,
          resources: [Function (anonymous)],
          allResources: [Function (anonymous)],
          isKnown: Promise { <pending> },
          isSecret: Promise { <pending> },
          promise: [Function (anonymous)],
          toString: [Function (anonymous)],
          toJSON: [Function (anonymous)]
        }
    
    # Example CLI output (truncated)
    Diagnostics:
      pulumi:pulumi:Stack (aws-iac-dev):
        Calling __str__ on an Output[T] is not supported.
        To get the value of an Output[T] as an Output[str] consider:
        1. o.apply(lambda v: f"prefix{v}suffix")
        See https://www.pulumi.com/docs/concepts/inputs-outputs for more details.
        This function may throw in a future version of Pulumi.
    
    # Example CLI output (truncated)
    Diagnostics:
      pulumi:pulumi:Stack (aws-go-dev):
        {0xc000137180}
    
    # Example CLI output (truncated)
    Diagnostics:
      pulumi:pulumi:Stack (aws-csharp-dev):
        Calling [ToString] on an [Output<T>] is not supported.
        To get the value of an Output<T> as an Output<string> consider:
        1. o.Apply(v => $"prefix{v}suffix")
        2. Output.Format($"prefix{hostname}suffix");
        See https://www.pulumi.com/docs/concepts/inputs-outputs for more details.
        This function may throw in a future version of Pulumi.
    
    # Example CLI output (truncated)
    Updating (pulumi/dev)
        Type                                          Name           Status              Info
     +   pulumi:pulumi:Stack                           aws-java-dev     created (1s)        391 messages
     +   └─ awsx:ec2:Vpc                               vpc            created (1s)
    ...
    ...
    
    # Nothing is printed
    
    Resources:
        + 34 created
    
    Duration: 2m17s
    
    This example is not applicable in YAML.
    

    This is where apply apply Apply Apply comes into play. There are many resources that have properties of type Output, meaning these property values only become known after the infrastructure has been provisioned. When a Pulumi program is executed with pulumi up, the apply apply Apply Apply function will wait for the resource to be created and for its properties to be resolved before printing the desired value of the property. This is not something a standard print | log statement is capable of doing.

    The syntax of apply apply Apply Apply is shown below:

    <resource>.<property-name>.apply(<property-name> => <function-to-apply>)
    
    <resource>.<property-name>.apply(<property-name> => <function-to-apply>)
    
    <resource>.<property-name>.apply(lambda <property-name>: <function-to-apply>)
    
    <resource>.<property-name>.ApplyT(func(<property-name> string) error {
        <function-to-apply>
        return nil
    })
    
    <resource>.<property-name>.Apply(<property-name> => {
        <function-to-apply>;
        return <property-name>;
    });
    
    <resource>.<property-name>().applyValue(<property-name> -> {
        <function-to-apply>;
        return null;
    });
    
    You can directly access resource properties without the use of Apply in YAML.
    

    The breakdown of the different parts of the syntax is as follows:

    • <resource> is the name of the resource (i.e. vpc)
    • <property-name> is the name of the property to retrieve (i.e. vpc_id)
    • <function-to-apply> is the function to apply against the value of the property

    This means that if you want to print out the value of the VPC ID, the program needs to look like the following:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const awsx = require("@pulumi/awsx");
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    vpc.vpcId.apply(id => console.log(`VPC ID: {id}`));
    
    import * as pulumi from "@pulumi/pulumi";
    import * as awsx from "@pulumi/awsx";
    
    const vpc = new awsx.ec2.Vpc("vpc");
    
    vpc.vpcId.apply(id => console.log(`VPC ID: {id}`));
    
    import pulumi
    import pulumi_awsx as awsx
    
    vpc = awsx.ec2.Vpc("vpc")
    
    vpc.vpc_id.apply(lambda id: print('VPC ID:', id))
    
    package main
    
    import (
        "fmt"
    	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ec2"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    
    		vpc, err := ec2.NewVpc(ctx, "vpc", nil)
    		if err != nil {
    			return err
    		}
    
            vpc.VpcId().ApplyT(func(id string) error {
                fmt.Printf("VPC ID: %s", id)
            	return nil
            })
    
    		return nil
    	})
    }
    
    A note on error handling The function ApplyT spawns a Goroutine to await the availability of the implicated dependencies. This function accepts a T or (T, error) signature; the latter accomodates for error handling. Alternatively, one may use the ApplyTWithContext function in which the provided context can be used to reject the output as canceled. Error handling may also be achieved using an error chan.
    using Pulumi;
    using System.Collections.Generic;
    using Pulumi.Awsx.Ec2;
    
    return await Deployment.RunAsync(() =>
    {
        var vpc = new Vpc("vpc");
    
        vpc.VpcId.Apply(id => { Console.WriteLine($"VPC ID: {id}"); return id; });
    
    });
    
    package myproject;
    
    import com.pulumi.Pulumi;
    import com.pulumi.awsx.ec2.Vpc;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
    
                var vpc = new Vpc("vpc");
    
                vpc.vpcId().applyValue(i -> {
                    System.out.println("VPC ID: " + i);
                    return null;
                });
    
            });
        }
    }
    
    # YAML does not have the Apply method, but you can access values directly.
    name: awsx-vpc-yaml
    runtime: yaml
    description: An example that creates a new VPC using the default settings.
    resources:
      vpc:
        type: awsx:ec2:Vpc
    outputs:
      vpcId: ${vpc.vpcId}
    

    The above example will wait for the value to be returned from the API and print it to the console as shown below:

    Updating (pulumi/dev)
    
         Type                 Name         Status     Info
         pulumi:pulumi:Stack  aws-iac-dev             1 message
    
    Diagnostics:
      pulumi:pulumi:Stack (aws-iac-dev):
        VPC ID: vpc-0f8a025738f2fbf2f
    
    Resources:
        34 unchanged
    
    Duration: 12s
    

    You can now see the value of the VPC ID property that you couldn’t see before when using a regular print | log statement.

    Accessing nested output values

    Sometimes an output has an object with deeply nested values, and there may be times where the values of these nested properties need to be passed as inputs to other resources. For example, let’s say you have created an AWS Certificate Manager certificate resource as shown below:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const aws = require("@pulumi/aws");
    
    let certCertificate = new aws.acm.Certificate("cert", {
        domainName: "example.com",
        validationMethod: "DNS",
    });
    
    import * as pulumi from "@pulumi/pulumi";
    import * as aws from "@pulumi/aws";
    
    let certCertificate = new aws.acm.Certificate("cert", {
        domainName: "example.com",
        validationMethod: "DNS",
    });
    
    import pulumi
    import pulumi_aws as aws
    
    certificate = aws.acm.Certificate('cert',
        domain_name='example.com',
        validation_method='DNS'
    )
    package main
    
    import (
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/acm"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    		_, err := acm.NewCertificate(ctx, "cert", &acm.CertificateArgs{
    			DomainName:       pulumi.String("example.com"),
    			ValidationMethod: pulumi.String("DNS"),
    		})
    		if err != nil {
    			return err
    		}
    		return nil
    	})
    }
    
    using Pulumi;
    using Pulumi.Aws.Acm;
    using System.Collections.Generic;
    
    return await Deployment.RunAsync(() =>
    {
        var cert = new Certificate("cert", new CertificateArgs
        {
            DomainName = "example",
            ValidationMethod = "DNS",
        });
    });
    
    package myproject;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.core.Output;
    import com.pulumi.aws.acm.Certificate;
    import com.pulumi.aws.acm.CertificateArgs;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
                var cert = new Certificate("cert",
                    CertificateArgs.builder()
                        .domainName("example")
                        .validationMethod("DNS")
                        .build());
            });
        }
    }
    
    name: aws-acm-certificate-yaml
    runtime: yaml
    
    resources:
      cert:
        type: aws:acm:Certificate
        properties:
          domainName: example.com
          validationMethod: DNS
    

    This resource will have outputs that resemble the following:

    # Example truncated output of the ACM certificate resource
    cert: {
        arn                      : "arn:aws:acm:eu-central-1..."
        certificate_authority_arn: ""
        certificate_body         : <null>
        certificate_chain        : <null>
        domain_name              : "example.com"
        domain_validation_options: [
            [0]: {
                domain_name          : "example.com"
                resource_record_name : "_0a822dde6347292b.example.com."
                resource_record_type : "CNAME"
                resource_record_value: "_527b1cdf2159204b.mhbtsbpdnt.acm-validations.aws."
            }
        ]
        ...
        ...
    }
    

    Suppose you want to validate your certificate by creating an Amazon Route 53 record. To do so, you will need to retrieve the value of the resource record from the ACM certificate. This value is nested in the domain validation options property of the certificate resource, which is an array. Because that value is an output, you would normally need to use apply apply Apply Apply to retrieve it:

    let certValidation = new aws.route53.Record("cert_validation", {
        records: [
            // Need to pass along a deep subproperty of this Output
            certCertificate.domainValidationOptions.apply(
                domainValidationOptions => domainValidationOptions[0].resourceRecordValue),
        ],
        ...
    });
    
    let certValidation = new aws.route53.Record("cert_validation", {
        records: [
            // Need to pass along a deep subproperty of this Output
            certCertificate.domainValidationOptions.apply(
                domainValidationOptions => domainValidationOptions[0].resourceRecordValue),
        ],
        ...
    });
    
    record = aws.route53.Record('validation',
        records=[
            # Need to pass along a deep subproperty of this Output
            certificate.domain_validation_options.apply(
                lambda domain_validation_options: domain_validation_options[0]['resourceRecordValue']
            )
        ],
        ...
    )
    
    record, err := route53.NewRecord(ctx, "validation", &route53.RecordArgs{
        Records: pulumi.StringArray{
            cert.DomainValidationOptions.ApplyT(func(opts []acm.CertificateDomainValidationOption) string {
                return *opts[0].ResourceRecordValue
            }).(pulumi.StringOutput),
        },
        ...
    })
    if err != nil {
        return err
    }
    
    var record = new Record("validation", new RecordArgs
    {
        Records = {
            cert.DomainValidationOptions.Apply(opts => opts[0].ResourceRecordValue!)
        },
        ...
    });
    
    var record = new Record("validation",
        RecordArgs.builder()
            .records(
                cert.domainValidationOptions()
                .applyValue(opts -> opts.get(0).resourceRecordValue().get())
                .applyValue(String::valueOf)
                .applyValue(List::of))
            .build());
    
    This example is not applicable in YAML.
    

    An easier way to access deeply nested properties is by using lifting. Lifting allows you to access properties and elements directly from the Output Output<T> Output[T] Output Output<T> itself without needing apply apply Apply Apply . Returning to the example above, your code can now be simplified as shown below:

    let certValidation = new aws.route53.Record("cert_validation", {
        records: [
            certCertificate.domainValidationOptions[0].resourceRecordValue
        ],
    ...
    
    let certValidation = new aws.route53.Record("cert_validation", {
        records: [
            certCertificate.domainValidationOptions[0].resourceRecordValue
        ],
    ...
    
    record = aws.route53.Record('validation',
        records=[
            certificate.domain_validation_options[0].resource_record_value
        ],
    ...
    
    record, err := route53.NewRecord(ctx, "validation", &route53.RecordArgs{
        Records: pulumi.StringArray{
            // Notes:
            // * `Index` looks up an index in an `ArrayOutput` and returns a new `Output`.
            // * Accessor methods like `ResourceRecordValue` lookup properties of a custom struct `Output` and return a new `Output`.
            // * `Elem` dereferences a `PtrOutput` to an `Output`, equivalent to `*`.
            cert.DomainValidationOptions.Index(pulumi.Int(0)).ResourceRecordValue().Elem(),
        },
        ...
    })
    if err != nil {
        return err
    }
    
    var record = new Record("validation", new RecordArgs
    {
        // Notes:
        // * `GetAt` looks up an index in an `Output<ImmutableArray<T>>` and returns a new `Output<T>`
        // * There are not yet accessor methods for referencing properties like `ResourceRecordValue` on an `Output<T>` directly,
        //   so the `Apply` is still needed for the property access.
        Records = cert.DomainValidationOptions.GetAt(0).Apply(opt => opt.ResourceRecordValue!),
    });
    
    // Lifting is currently not supported in Java.
    
    resources:
      cert:
        type: aws:acm:Certificate
        properties:
          domainName: example
          validationMethod: DNS
      record:
        type: aws:route53:Record
        properties:
          records:
            # YAML handles inputs and outputs transparently.
            - ${cert.domainValidationOptions[0].resourceRecordValue}
    

    This approach is easier to read and write and does not lose any important dependency information that is needed to properly create and maintain the stack. This approach doesn’t work in all cases, but when it does, it can be a great help.

    Creating new output values

    Outputs and Strings

    Outputs that return to the engine as strings cannot be used directly in operations such as string concatenation until the output value has returned to Pulumi. In these scenarios, you’ll need to wait for the value to return using apply.

    For example, the following code creates an HTTPS URL from the DNS name (the plain value) of a virtual machine (in this case an EC2 instance):

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const aws = require("@pulumi/aws");
    
    const server = new aws.ec2.Instance("web-server", {
        ami: "ami-0319ef1a70c93d5c8",
        instanceType: "t2.micro",
    });
    
    const url = server.publicDns.apply(dnsName => `https://${dnsName}`);
    
    exports.InstanceUrl = url;
    
    import * as pulumi from "@pulumi/pulumi";
    import * as aws from "@pulumi/aws";
    
    const server = new aws.ec2.Instance("web-server", {
        ami: "ami-0319ef1a70c93d5c8",
        instanceType: "t2.micro",
    });
    
    const url = server.publicDns.apply(dnsName => `https://${dnsName}`);
    
    export const InstanceUrl = url;
    
    import pulumi
    import pulumi_aws as aws
    
    server = aws.ec2.Instance(
        "web-server",
        ami="ami-0319ef1a70c93d5c8",
        instance_type="t2.micro",
    )
    
    url = instance.public_dns.apply(
        lambda dns_name: "https://" + dns_name
    )
    
    pulumi.export("InstanceUrl", url)
    
    package main
    
    import (
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    		server, err := ec2.NewInstance(ctx, "web-server", &ec2.InstanceArgs{
    			Ami:                 pulumi.String("ami-0319ef1a70c93d5c8"),
    			InstanceType:        pulumi.String("t2.micro"),
    		})
    		if err != nil {
    			return err
    		}
    
            url := server.PublicDns.ApplyT(func(dns string) string {
    			return "https://" + dns
    		}).(pulumi.StringOutput)
    
            ctx.Export("InstanceUrl", url)
    		return nil
    	})
    }
    
    using Pulumi;
    using Pulumi.Aws.Ec2;
    using Pulumi.Aws.Ec2.Inputs;
    using System.Collections.Generic;
    
    return await Deployment.RunAsync(() =>
    {
        var server = new Instance("web-server", new InstanceArgs {
            Ami = "ami-0319ef1a70c93d5c8",
            InstanceType = "t2.micro",
        });
    
        var url = server.PublicDns.Apply(dns => $"https://{dns}");
    
        return new Dictionary<string, object?>
        {
            ["InstanceUrl"] = url,
        };
    });
    
    package myproject;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.aws.ec2.Instance;
    import com.pulumi.aws.ec2.InstanceArgs;
    import com.pulumi.aws.ec2.SecurityGroup;
    import com.pulumi.aws.ec2.SecurityGroupArgs;
    import com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs;
    
    import java.util.List;
    
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var server = new Instance("web-server",
                InstanceArgs.builder()
                    .ami("ami-0319ef1a70c93d5c8")
                    .instanceType("t2.micro")
                    .build());
    
            var url = server.publicDns().applyValue(dns -> "https://" + dns);
    
            ctx.export("InstanceUrl", url);
        }
    }
    
    # YAML does not have the Apply method, but you can access values directly.
    name: aws-ec2-instance-yaml
    runtime: yaml
    description: An example that shows how to create an EC2 instance and security group.
    resources:
      server:
        type: aws:ec2:Instance
        properties:
          ami: ami-0319ef1a70c93d5c8
          instanceType: t2.micro
    outputs:
      InstanceUrl: https://${server.publicDns}
    

    The CLI output of this code would look something like the following:

    Updating (pulumi/dev)
    
         Type                 Name         Status
         pulumi:pulumi:Stack  aws-iac-dev
     -   └─ awsx:ec2:Vpc      vpc
    
    Outputs:
        InstanceUrl: "https://ec2-52-59-110-22.eu-central-1.compute.amazonaws.com"
    
    Duration: 5s
    

    The result of the call to apply apply Apply Apply is a new Output, meaning the url variable is now of type Output. This variable will wait for the new value to be returned from the apply apply Apply Apply function, and any dependencies of the original output (i.e. the public DNS property of the server resource) are also kept in the resulting Output.

    Outputs and JSON

    Often in the course of working with web technologies, you encounter JavaScript Object Notation (JSON) which is a popular specification for representing data. In many scenarios, you’ll need to embed resource outputs into a JSON string. In these scenarios, you need to first wait for the returned output, then build the JSON string.

    For example, let’s say you want to create an S3 bucket and a bucket policy that allows the Lambda service to write objects to that bucket. The example below shows how to use apply to create the bucket policy JSON object using an output value from the S3 bucket resource (in this case the bucket’s ARN):

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const aws = require("@pulumi/aws");
    
    // Create an S3 bucket
    const s3Bucket = new aws.s3.Bucket("myBucket");
    
    // IAM Policy Document that allows the Lambda service to write to the S3 bucket
    const s3BucketPolicyDocument = s3Bucket.arn.apply(arn =>
        JSON.stringify({
            Version: "2012-10-17",
            Statement: [
                {
                    Effect: "Allow",
                    Principal: { Service: "lambda.amazonaws.com" },
                    Action: ["s3:PutObject", "s3:PutObjectAcl"],
                    Resource: `${arn}/*`,
                },
            ],
        }),
    );
    
    // Attach the policy to the bucket
    const s3BucketPolicy = new aws.s3.BucketPolicy("myBucketPolicy", {
        bucket: s3Bucket.id,
        policy: s3BucketPolicyDocument,
    });
    
    // Export the names and ARNs of the created resources
    exports.bucketName = s3Bucket.id;
    exports.bucketArn = s3Bucket.arn;
    
    import * as pulumi from "@pulumi/pulumi";
    import * as aws from "@pulumi/aws";
    
    // Create an S3 bucket
    const s3Bucket = new aws.s3.Bucket("myBucket");
    
    // IAM Policy Document that allows the Lambda service to write to the S3 bucket
    const s3BucketPolicyDocument = s3Bucket.arn.apply(arn =>
        JSON.stringify({
            Version: "2012-10-17",
            Statement: [
                {
                    Effect: "Allow",
                    Principal: { Service: "lambda.amazonaws.com" },
                    Action: ["s3:PutObject", "s3:PutObjectAcl"],
                    Resource: `${arn}/*`,
                },
            ],
        }),
    );
    
    // Attach the policy to the bucket
    const s3BucketPolicy = new aws.s3.BucketPolicy("myBucketPolicy", {
        bucket: s3Bucket.id,
        policy: s3BucketPolicyDocument,
    });
    
    // Export the names and ARNs of the created resources
    export const bucketName = s3Bucket.id;
    export const bucketArn = s3Bucket.arn;
    
    import pulumi
    import pulumi_aws as aws
    import json
    
    # Create an S3 bucket
    s3_bucket = aws.s3.Bucket("myBucket")
    
    # IAM Policy Document that allows the Lambda service to write to the S3 bucket
    s3_bucket_policy_document = s3_bucket.arn.apply(
        lambda arn: json.dumps(
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {"Service": "lambda.amazonaws.com"},
                        "Action": ["s3:PutObject", "s3:PutObjectAcl"],
                        "Resource": f"{arn}/*",
                    }
                ],
            }
        )
    )
    
    # Attach the policy to the bucket
    s3_bucket_policy = aws.s3.BucketPolicy(
        "myBucketPolicy",
        bucket=s3_bucket.id,
        policy=s3_bucket_policy_document,
    )
    
    # Export the names and ARNs of the created resources
    pulumi.export("bucket_name", s3_bucket.id)
    pulumi.export("bucket_arn", s3_bucket.arn)
    
    package main
    
    import (
    	"fmt"
    
    	"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/s3"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    		// Create an S3 bucket
    		s3Bucket, err := s3.NewBucket(ctx, "myBucket", nil)
    		if err != nil {
    			return err
    		}
    
    		// IAM Policy Document that allows the Lambda service to write to the S3 bucket
    		s3Bucket.Arn.ApplyT(func(arn string) (string, error) {
    			policy := fmt.Sprintf(`{
    				"Version": "2012-10-17",
    				"Statement": [{
    					"Effect": "Allow",
    					"Principal": {"Service": "lambda.amazonaws.com"},
    					"Action": ["s3:PutObject", "s3:PutObjectAcl"],
    					"Resource": "%s/*"
    				}]
    			}`, arn)
    
    			// Attach the policy to the bucket
    			_, err := s3.NewBucketPolicy(ctx, "myBucketPolicy", &s3.BucketPolicyArgs{
    				Bucket: s3Bucket.ID(),
    				Policy: pulumi.String(policy),
    			})
    			if err != nil {
    				return "", err
    			}
    
    			return "", nil
    		})
    
    		// Export the names and ARNs of the created resources
    		ctx.Export("bucketName", s3Bucket.ID())
    		ctx.Export("bucketArn", s3Bucket.Arn)
    
    		return nil
    	})
    }
    
    using Pulumi;
    using Pulumi.Aws.Iam;
    using Pulumi.Aws.S3;
    using System.Collections.Generic;
    using System.Text.Json;
    
    return await Deployment.RunAsync(() =>
    {
        var bucket = new Bucket("myBucket");
    
        var s3BucketPolicyDocument = bucket.Arn.Apply(arn => JsonSerializer.Serialize(new
        {
            Version = "2012-10-17",
            Statement = new[]
            {
                new
                {
                    Effect = "Allow",
                    Principal = new { Service = "lambda.amazonaws.com" },
                    Action = new[] { "s3:PutObject", "s3:PutObjectAcl" },
                    Resource = $"{arn}/*"
                }
            }
        }));
    
        var bucketPolicy = new BucketPolicy("myBucketPolicy", new BucketPolicyArgs
        {
            Bucket = bucket.Id,
            Policy = s3BucketPolicyDocument
        });
    
        return new Dictionary<string, object?>
        {
            ["bucketName"] = bucket.Id,
            ["bucketArn"] = bucket.Arn
        };
    });
    
    package myproject;
    
    import com.pulumi.Pulumi;
    import com.pulumi.aws.s3.Bucket;
    import com.pulumi.aws.s3.BucketPolicy;
    import com.pulumi.aws.s3.BucketPolicyArgs;
    import static com.pulumi.codegen.internal.Serialization.*;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
                var bucket = new Bucket("myBucket");
    
                var policyDocument = bucket.arn().applyValue(arn -> serializeJson(
                    jsonObject(
                        jsonProperty("Version", "2012-10-17"),
                        jsonProperty("Statement", jsonArray(jsonObject(
                            jsonProperty("Effect", "Allow"),
                            jsonProperty("Action", jsonArray("s3:PutObject", "s3:PutObjectAcl")),
                            jsonProperty("Principal", jsonObject(
                                jsonProperty("Service", "lambda.amazonaws.com")
                            )),
                            jsonProperty("Resource", arn + "/*")
                        )))
                    )
                ));
    
                var bucketPolicy = new BucketPolicy("myBucketPolicy", BucketPolicyArgs.builder()
                    .bucket(bucket.id())
                    .policy(policyDocument)
                    .build());
    
                ctx.export("bucketName", bucket.id());
                ctx.export("bucketArn", bucket.arn());
            });
        }
    }
    
    name: aws-s3bucket-bucketpolicy-yaml
    runtime: yaml
    description: An example that deploys an S3 bucket and bucket policy on AWS.
    
    resources:
      myBucket:
        type: aws:s3/bucket:Bucket
    
      myBucketPolicy:
        type: aws:s3/bucketPolicy:BucketPolicy
        properties:
          bucket: ${myBucket.id}
          policy:
            fn::toJSON:
              Version: "2012-10-17"
              Statement:
                - Effect: "Allow"
                  Principal:
                    Service: "lambda.amazonaws.com"
                  Action:
                    - "s3:PutObject"
                    - "s3:PutObjectAcl"
                  Resource: "${myBucket.arn}/*"
    
    outputs:
      bucket_name: ${myBucket.id}
      bucket_arn: ${myBucket.arn}
    

    This operation is so common that Pulumi provides first-class helper functions to make it much easier. These helper functions can:

    • convert native objects into JSON strings (i.e., serialization)
    • convert JSON strings into native objects (i.e., deserialization)

    Converting JSON objects to strings

    If you need to construct a JSON string using output values from Pulumi resources, you can easily do so using a JSON stringify helper. These helpers unwrap Pulumi outputs without requiring the use of apply and produce JSON string outputs suitable for passing to other resources as inputs.

    In this example, a JSON string for an S3 bucket policy is composed with two outputs: the authenticated user’s account ID and the bucket’s computed Amazon Resource Name (ARN). Here, since the statement’s Resource property uses only an ARN, the ARN output can be passed as a value directly. To compose more complex values, you can either use apply or all to assemble and return a new output or, for string values, use a string helper such as below, which composes the ARN for the Principal property using the account ID output:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const aws = require("@pulumi/aws");
    
    // Get the account ID of the current user as a Pulumi output.
    const accountID = aws.getCallerIdentityOutput().accountId;
    
    // Create an S3 bucket.
    const bucket = new aws.s3.Bucket("my-bucket");
    
    // Create an S3 bucket policy allowing anyone in the account to list the contents of the bucket.
    const policy = new aws.s3.BucketPolicy("my-bucket-policy", {
        bucket: bucket.id,
        policy: pulumi.jsonStringify({
            Version: "2012-10-17",
            Statement: [
                {
                    Effect: "Allow",
                    Principal: {
                        AWS: pulumi.interpolate`arn:aws:iam::${accountID}:root`,
                    },
                    Action: "s3:ListBucket",
                    Resource: bucket.arn,
                },
            ],
        }),
    });
    
    // Export the name of the bucket
    exports.bucketName = bucket.id;
    
    import * as pulumi from "@pulumi/pulumi";
    import * as aws from "@pulumi/aws";
    
    // Get the account ID of the current user as a Pulumi output.
    const accountID = aws.getCallerIdentityOutput().accountId;
    
    // Create an S3 bucket.
    const bucket = new aws.s3.Bucket("my-bucket");
    
    // Create an S3 bucket policy allowing anyone in the account to list the contents of the bucket.
    const policy = new aws.s3.BucketPolicy("my-bucket-policy", {
        bucket: bucket.id,
        policy: pulumi.jsonStringify({
            Version: "2012-10-17",
            Statement: [
                {
                    Effect: "Allow",
                    Principal: {
                        AWS: pulumi.interpolate`arn:aws:iam::${accountID}:root`,
                    },
                    Action: "s3:ListBucket",
                    Resource: bucket.arn,
                },
            ],
        }),
    });
    
    // Export the name of the bucket.
    export const bucketName = bucket.id;
    
    import pulumi
    import pulumi_aws as aws
    
    # Get the account ID of the current user as a Pulumi output.
    account_id = aws.get_caller_identity_output().apply(
        lambda identity: identity.account_id
    )
    
    # Create an S3 bucket.
    bucket = aws.s3.Bucket("my-bucket")
    
    # Create an S3 bucket policy allowing anyone in the account to list the contents of the bucket.
    policy = aws.s3.BucketPolicy(
        "my-bucket-policy",
        bucket=bucket.id,
        policy=pulumi.Output.json_dumps(
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": pulumi.Output.format("arn:aws:iam::{0}:root", account_id)
                        },
                        "Action": "s3:ListBucket",
                        "Resource": bucket.arn,
                    }
                ],
            }
        ),
    )
    
    # Export the name of the bucket
    pulumi.export("bucketName", bucket.id)
    
    package main
    
    import (
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws"
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/s3"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    
    		// Get the account ID of the current user as a Pulumi Output.
    		callerIdentity, err := aws.GetCallerIdentity(ctx, nil, nil)
    		if err != nil {
    			return err
    		}
    		accountID := callerIdentity.AccountId
    
    		// Create an AWS resource (S3 Bucket)
    		bucket, err := s3.NewBucket(ctx, "my-bucket", nil)
    		if err != nil {
    			return err
    		}
    
    		// Create an S3 bucket policy allowing anyone in the account to list the contents of the bucket.
    		_, err = s3.NewBucketPolicy(ctx, "my-bucket-policy", &s3.BucketPolicyArgs{
    			Bucket: bucket.ID(),
    			Policy: pulumi.JSONMarshal(map[string]interface{}{
    				"Version": pulumi.ToOutput("2012-10-17"),
    				"Statement": pulumi.ToOutput([]interface{}{
    					pulumi.ToMapOutput(map[string]pulumi.Output{
    						"Effect": pulumi.ToOutput("Allow"),
    						"Principal": pulumi.ToMapOutput(map[string]pulumi.Output{
    							"AWS": pulumi.Sprintf("arn:aws:iam::%s:root", accountID),
    						}),
    						"Action":   pulumi.ToOutput("s3:ListBucket"),
    						"Resource": bucket.Arn,
    					}),
    				}),
    			}),
    		})
    		if err != nil {
    			return err
    		}
    
    		// Export the name of the bucket
    		ctx.Export("bucketName", bucket.ID())
    		return nil
    	})
    }
    
    using System.Collections.Generic;
    using Pulumi;
    using Pulumi.Aws.S3;
    
    return await Deployment.RunAsync(() =>
    {
        // Get the account ID of the current user as a Pulumi output.
        var accountID = Pulumi.Aws.GetCallerIdentity.Invoke().Apply(identity => identity.AccountId);
    
        // Create an S3 bucket.
        var bucket = new Bucket("my-bucket");
    
        // Create an S3 bucket policy allowing anyone in the account to list the contents of the bucket.
        var policy = new BucketPolicy("my-bucket-policy", new BucketPolicyArgs
            {
                Bucket = bucket.Id,
                Policy = Output.JsonSerialize(Output.Create(
                    new
                    {
                        Version = "2012-10-17",
                        Statement = new[]
                        {
                            new
                            {
                                Effect = "Allow",
                                Principal = new
                                {
                                    AWS = Output.Format($"arn:aws:iam::{accountID}:root")
                                },
                                Action = "s3:ListBucket",
                                Resource = bucket.Arn,
                            }
                        }
                    }
                ))
            }
        );
    
        // Export the name of the bucket.
        return new Dictionary<string, object?> { ["bucketName"] = bucket.Id };
    });
    

    Converting JSON strings to outputs

    If you have an output in the form of a JSON string and you need to interact with it like you would a regular JSON object, you can use Pulumi’s parsing helper function.

    In the example below, you can parse a JSON string into a JSON object and then, inside of an apply, manipulate the object to remove all of the policy statements:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    
    const jsonIAMPolicy = pulumi.output(`{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "s3:ListAllMyBuckets",
                    "s3:GetBucketLocation"
                ],
                "Resource": "*"
            },
            {
                "Sid": "VisualEditor1",
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::my-bucket"
            }
        ]
    }`);
    
    // Parse the string output.
    const policyWithNoStatements = pulumi.jsonParse(jsonIAMPolicy).apply(policy => {
        // Empty the policy's Statements list.
        policy.Statement = [];
        return policy;
    });
    
    // Export the modified policy.
    exports.policy = policyWithNoStatements;
    
    import * as pulumi from "@pulumi/pulumi";
    
    const jsonIAMPolicy = pulumi.output(`{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "s3:ListAllMyBuckets",
                    "s3:GetBucketLocation"
                ],
                "Resource": "*"
            },
            {
                "Sid": "VisualEditor1",
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::my-bucket"
            }
        ]
    }`);
    
    // Parse the string output.
    const policyWithNoStatements: pulumi.Output<object> = pulumi.jsonParse(jsonIAMPolicy).apply(policy => {
        // Empty the policy's Statements list.
        policy.Statement = [];
        return policy;
    });
    
    // Export the modified policy.
    export const policy = policyWithNoStatements;
    
    import pulumi
    
    json_iam_policy = pulumi.Output.from_input(
        """
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "s3:ListAllMyBuckets",
                    "s3:GetBucketLocation"
                ],
                "Resource": "*"
            },
            {
                "Sid": "VisualEditor1",
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::my-bucket"
            }
        ]
    }
    """
    )
    
    
    def update_policy(policy):
        # Empty the policy's Statements list.
        policy.update({"Statement": []})
        return policy
    
    
    # Parse the string output.
    policy_with_no_statements = pulumi.Output.json_loads(json_iam_policy).apply(
        lambda policy: update_policy
    )
    
    # Export the modified policy.
    pulumi.export("policy", policy_with_no_statements)
    
    package main
    
    import (
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    
    		jsonIAMPolicy := pulumi.ToOutput(`{
    		    "Version": "2012-10-17",
    		    "Statement": [
    		        {
    		            "Sid": "VisualEditor0",
    		            "Effect": "Allow",
    		            "Action": [
    		                "s3:ListAllMyBuckets",
    		                "s3:GetBucketLocation"
    		            ],
    		            "Resource": "*"
    		        },
    		        {
    		            "Sid": "VisualEditor1",
    		            "Effect": "Allow",
    		            "Action": "s3:*",
    		            "Resource": "arn:aws:s3:::my-bucket"
    		        }
    		    ]
    		}`).(pulumi.StringInput)
    
    		// Parse the string output.
    		policyWithNoStatements := pulumi.JSONUnmarshal(jsonIAMPolicy).ApplyT(
    			func(v interface{}) (interface{}, error) {
    
    				// Empty the policy's Statements list.
    				v.(map[string]interface{})["Statement"] = []pulumi.ArrayOutput{}
    				return v, nil
    			},
    		)
    
    		// Export the modified policy.
    		ctx.Export("policy", policyWithNoStatements)
    		return nil
    	})
    }
    
    using System.Collections.Generic;
    using Pulumi;
    
    return await Deployment.RunAsync(() =>
    {
        var jsonIAMPolicy = Output.Create(
            @"
            {
                ""Version"": ""2012-10-17"",
                ""Statement"": [
                    {
                        ""Sid"": ""VisualEditor0"",
                        ""Effect"": ""Allow"",
                        ""Action"": [
                            ""s3:ListAllMyBuckets"",
                            ""s3:GetBucketLocation""
                        ],
                        ""Resource"": ""*""
                    },
                    {
                        ""Sid"": ""VisualEditor1"",
                        ""Effect"": ""Allow"",
                        ""Action"": [
                            ""s3:*""
                        ],
                        ""Resource"": ""arn:aws:s3:::my-bucket""
                    }
                ]
            }
        "
        );
    
        // Parse the Output<string> into a C# Dictionary.
        var policyWithNoStatements = Output
            .JsonDeserialize<Dictionary<string, object?>>(jsonIAMPolicy)
            .Apply(policy =>
            {
                // Empty the policy's Statements list.
                policy["Statement"] = Output.Create(new List<Dictionary<string, object?>> { });
                return policy;
            });
    
        // Export the modified policy.
        return new Dictionary<string, object?> { ["policy"] = policyWithNoStatements, };
    });
    

    For more details view the Go documentation.

    For more details view the .NET documentation.

      PulumiUP 2024. Watch On Demand.