Jordan Taylor
justjordant

justjordant

Day 6 - Pulumi Inputs and Outputs

Day 6 - Pulumi Inputs and Outputs

Jordan Taylor's photo
Jordan Taylor
·May 14, 2022·

4 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

  • Day 6 - Pulumi Input and Outputs

Day 6 - Pulumi Input and Outputs

What are Inputs and Outputs?

All resources args in Pulumi can accept Inputs; Inputs are values of type Input<T>, a kind that permits either a raw value of a given type like string, integer, boolean, list, map, and so on.

Here is an example of AWS S3 bucket Inputs, to name a few.

image.png

All resource properties on the instance object itself are outputs. Outputs are values of type Output<T>.

If we can a look at the Pulumi documentation for [AWS S3](aws.s3.Bucket | Pulumi buckets; we can see that we have the following list of Outputs.

image.png

How can we use Inputs and Outputs?

In the following ComponentResource we can see that we are setting Outputs to both Id and Name; When creating an instance of this class we will now have access to Id and Name that we could in turn now pass into another class that we may need to storage account Id for.

A good example of this in the Azure space is with LogAnalytics we need to have a storage account to point a location to where we would like to have our Logs archived!

public class StorageAccount : ComponentResource  
{  
    [Output("id")]   
public Output<string> Id { get; private set; }  

    [Output("name")]   
public Output<string> Name { get; private set; }  

    public PrivateStorageAccount(string name, PrivateStorageAccountArgs args,  
        ComponentResourceOptions? options = null, bool remote = false) :  
        base("StorageAccount", name, args, options, remote)  
    {        var storageAccount = new StorageAccount($"{name}", new StorageAccountArgs  
        {  
            AccountName = name.Replace("-",""),  
            Kind = Kind.StorageV2,  
            Sku = new SkuArgs  
            {  
                Name = SkuName.Standard_GRS  
            },  
            AllowBlobPublicAccess = args.AllowBlobPublicAccess,  
            EnableHttpsTrafficOnly = true,  
            Location = args.ResourceGroupLocation,  
            MinimumTlsVersion = MinimumTlsVersion.TLS1_2,  
            ResourceGroupName = args.ResourceGroupName,  
            Tags = args.Tags,  
        },  
        new CustomResourceOptions  
        {  
            Parent = this  
        });  
        Id = storageAccount.Id;  
        Name = storageAccount.Name;  
    }  
}

By passing output from one resource as an input to another resource, Pulumi captures dependencies automatically. When these dependencies are captured, physical infrastructure resources will not be created or updated until all their dependencies are available and current.

It is not possible to obtain the actual raw values of outputs immediately due to their asynchronous nature. If you need to access an output’s raw value—for example, to compute a derived, new value, or because you want to log it—you have these options:

Apply: a callback that receives the raw value, and computes a new output

Lifting: directly read the properties of an output value

Interpolation: concatenate string outputs with other strings directly

Using Apply

Use Apply to access the raw value of output and transform that value into a new value. This method accepts a callback that will be invoked with the raw value, once that value is available.

Here we can see how we would grab the DNS name of a VM and apply this to a URL format.

var url = virtualmachine.DnsName.Apply(dnsName => "https://" + dnsName);

Access an Output by Lifting

If you need to use the value of a property as an argument in another resource's constructor, you can usually just access Output directly.

var cert = new Certificate("cert", new CertificateArgs
{
    DomainName = "example",
    ValidationMethod = "DNS",
});

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!),
});

This approach doesn’t work in all cases, but when it does 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, it can be a great help.

Outputs and Strings.

Say you want to create a URL from the hostname and port output values. You can do this using apply and all or we can use Output.Format

// Format takes a FormattableString and expands outputs correctly:
var url = Output.Format($"http://{hostname}:{port}/");

Why Inputs and Outputs?

Certain values are not available to us at runtime; this is where Inputs and Outputs come into play! They can help us set and access values that we need for other resources somewhere after runtime.

We have different options to use when we are facing this issue; so don't forget to reference the Inputs & Outputs

Happy coding my friends!

Did you find this article valuable?

Support Jordan Taylor by becoming a sponsor. Any amount is appreciated!

See recent sponsors Learn more about Hashnode Sponsors
 
Share this