1. Docs
  2. Pulumi IaC
  3. Concepts
  4. Functions
  5. Provider functions

Provider functions

    A provider may make functions available in its SDK as well as resource types. These “provider functions” are often for calling a platform API to get a value that is not part of a resource.

    For example, the AWS provider includes the function aws.ecs.getAmi:

    import * as aws from "@pulumi/aws";
    
    // Wrapping our program in an immediately invoked async function allows us to
    // use the "async" keyword.
    (async () => {
      const latestAmi = await aws.ec2.getAmi({
        owners: ["amazon"],
        mostRecent: true,
        filters: [
          { name: "name", values: ["amzn2-ami-hvm-*"] },
          { name: "architecture", values: ["x86_64"] }
        ]
      });
    
      new aws.ec2.Instance("web-server", {
        ami: latestAmi.imageId,
        instanceType: "t3.micro",
      });
    })();
    
    import pulumi_aws as aws
    
    latest_ami = aws.ec2.get_ami(
        owners=["amazon"],
        most_recent=True,
        filters=[
            {"name": "name", "values": ["amzn2-ami-hvm-*"]},
            {"name": "architecture", "values": ["x86_64"]}
        ]
    )
    
    instance = aws.ec2.Instance(
        "web-server",
        ami=latest_ami.image_id,
        instance_type="t3.micro"
    )
    
    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 {
      latestAmi, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
       Owners:     []string{"amazon"},
       MostRecent: pulumi.BoolRef(true),
       Filters: []ec2.GetAmiFilter{
        {
         Name:   "name",
         Values: []string{"amzn2-ami-hvm-*"},
        },
        {
         Name:   "architecture",
         Values: []string{"x86_64"},
        },
       },
      }, nil)
      if err != nil {
       return err
      }
    
      _, err = ec2.NewInstance(ctx, "web-server", &ec2.InstanceArgs{
       Ami:          pulumi.String(latestAmi.ImageId),
       InstanceType: pulumi.String("t3.micro"),
      })
      if err != nil {
       return err
      }
    
      return nil
     })
    }
    
    using Pulumi;
    using Aws = Pulumi.Aws;
    
    return await Deployment.RunAsync(() =>
    {
        var latestAmi = Aws.Ec2.GetAmi.Invoke(new Aws.Ec2.GetAmiInvokeArgs
        {
            Owners = { "amazon" },
            MostRecent = true,
            Filters =
                  {
                      new Aws.Ec2.Inputs.GetAmiFilterInputArgs
                      {
                          Name = "name",
                          Values = { "amzn2-ami-hvm-*" }
                      },
                      new Aws.Ec2.Inputs.GetAmiFilterInputArgs
                      {
                          Name = "architecture",
                          Values = { "x86_64" }
                      }
                  }
        });
    
        var instance = new Aws.Ec2.Instance("web-server", new Aws.Ec2.InstanceArgs
        {
            Ami = latestAmi.Apply(ami => ami.ImageId),
            InstanceType = "t3.micro"
        });
    });
    
    package myproject;
    
    import com.pulumi.*;
    import com.pulumi.aws.ec2.Ec2Functions;
    import com.pulumi.aws.ec2.Instance;
    import com.pulumi.aws.ec2.InstanceArgs;
    import com.pulumi.aws.ec2.inputs.GetAmiArgs;
    import com.pulumi.aws.ec2.inputs.GetAmiFilterArgs;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var latestAmi = Ec2Functions.getAmi(GetAmiArgs.builder()
                    .owners("amazon")
                    .mostRecent(true)
                    .filters(
                            GetAmiFilterArgs.builder()
                                    .name("name")
                                    .values("amzn2-ami-hvm-*")
                                    .build(),
                            GetAmiFilterArgs.builder()
                                    .name("architecture")
                                    .values("x86_64")
                                    .build())
                    .build());
    
            new Instance("web-server", InstanceArgs.builder()
                    .ami(latestAmi.applyValue(ami -> ami.imageId()))
                    .instanceType("t3.micro")
                    .build());
        }
    }
    
    name: provider-functions
    runtime: yaml
    
    variables:
      lastestAmi:
        fn::invoke:
          function: aws:ec2/getAmi:getAmi
          arguments:
            filters:
              - name: name
                values: ["amzn2-ami-hvm-*"]
              - name: architecture
                values: ["x86_64"]
            owners: ["amazon"]
            mostRecent: true
    
    resources:
      myInstance:
        type: aws:ec2:Instance
        properties:
          ami: ${lastestAmi.imageId}
          instanceType: "t3.micro"
    
    Bridged providers, which take a Terraform provider as an underlying dependency, expose Terraform data sources in the upstream Terraform provider as provider functions in the corresponding Pulumi provider.

    Direct form and output form

    Provider functions are exposed in each language as regular functions, in two variations:

    1. The direct form accepts plain arguments (e.g., string, as opposed to pulumi.Input<string>) and returns an asynchronous value (e.g., a Promise in Node.js, a Task in Python, etc.) or blocks until the result is available. These functions are typically named, e.g., getX().
    2. The output form accepts Pulumi Inputs (or plain values) as arguments and returns a Pulumi Output as a result. For more information on these types, see Inputs and Outputs. These functions are typically named, e.g., getXOutput().

    The Pulumi Registry contains authoritative documentation for all provider functions.

    Invoke options

    In addition to function arguments, provider functions also accept “invoke options”, similar to the way Pulumi resources accept resource options. Invoke options may be specified either as an object or as a list of arguments depending on the language you’re writing your Pulumi program in. The available options are:

    • dependsOn: An array of resources that this function depends on. This option is only available in the Output form of a provider function. See Choosing between direct form and output form for a full explanation.
    • parent: Supply a parent resource for this function call. Much like the parent resource option, the parent will be consulted when determining the provider to use.
    • provider: Pass an explicitly configured provider to use for this function call, instead of using the default provider. This is useful, for example, if you want to invoke a function in each of a set of AWS regions.

    The following options are also available, but are deprecated and should not be used in modern Pulumi programs as the functionality they control are commonly handled when you install a provider package:

    • pluginDownloadURL: Pass a URL from which the provider plugin should be fetched. This may be necessary for third-party packages such as those not hosted at https://get.pulumi.com.
    • version: Pass a provider plugin version that should be used when invoking the function.
    • async: This option is deprecated and will be removed in a future release.

    When your function will execute

    While the direct and output forms of a provider function will both return the same data when they are invoked, the two forms differ in when they are executed when running your Pulumi program:

    • Direct form functions execute just like any other function call in your Pulumi program’s language. Since direct form functions do not accept Pulumi Inputs and Outputs, they are not tracked by the Pulumi engine the way resources are, and do not participate in the dependency graph.
    • Output form functions are tracked by the Pulumi engine because they take Inputs as arguments and return Outputs as return values and therefore participate in the dependency graph. This means that Pulumi will ensure that all input values to the function are resolved before the function is invoked. (This is why dependsOn is only an option for the output form of a function.)

    Choosing between direct form and output form

    There are several common scenarios where either direct form or output form must or should be used:

    • If you need a provider function’s result to determine whether a resource should be created at all, you must use the provider function’s the direct form. The direct form of a function executes while the Pulumi engine is formulating the dependency graph (that is, determining what resources need to be created, updated, or deleted), so in order to figure out whether a resource belongs in the graph at all, that decision has to always be calculated up front.
    • If you need resources to be created or updated before the function is invoked, you should use the provider function’s output form. (It is possible to use the direct form in this case, but it requires wrapping the call in an apply, which can be awkward from a readability standpoint.) Dependencies in the output form of a function are tracked identically to resources: all inputs to the function must be resolved before the function executes. If you need to specify a dependency that isn’t already implied by an input to the function’s arguments, you can use the dependsOn function option to specify additional dependencies (just like you can with resources).

    Pulumi recommends you choose the output form of a function unless you have a specific need for the direct form. We make this recommendation because:

    1. The output form reduces mental overhead in that it allows your program to stick with a single asynchronous programming mental model (Pulumi inputs and outputs) as opposed to also having to worry about Promises (TypeScript), TaskResults (.NET), etc.
    2. Syntactically, it’s slightly more terse.

    Assuming there is no specific reason to choose one or the other, the choice between the two forms is ultimately a preference: there is no significant difference in either performance or code maintainability between the two forms.

      IDP Builder Course. Register Now.