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.
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.
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!