When you create a deployment, you might want to expose key properties of your configurations or templates for other templates or users to consume. For example, you might want to expose the IP address of a database created in a template so users can easily reference the IP when configuring their own templates.
You can use the outputs section in your template or configuration to define a list of key/values pairs that users can call. In the outputs section, you define arbitrary keys and set the value of the keys to a reference, a template property, or an environment variable. Users can consume outputs to access key information about resources created by the template. For example, you can declare an output called databaseIP that references the IP address of an instance hosting a database and users can reference that output in other templates in the same deployment.
Before you begin
- If you want to use the command-line examples in this guide, install the `gcloud` command-line tool.
- If you want to use the API examples in this guide, set up API access.
- Understand how to create a basic configuration.
Example
Here is an example template with outputs:
mongodb.jinja {% set MASTER = env["name"] + "-" + env["deployment"] + "-mongodb" %} resources: - name: {{ MASTER }} type: instance ... outputs: - name: databaseIp value: $(ref.{{ MASTER }}.network[0].ip) # Treated as a string during expansion - name: databasePort value: 88
The outputs section declares two properties: databaseIp and databasePort. databaseIp uses a reference that resolves to the network IP address of the master resource, while databasePort is a static value. In another template, you can import mongodb.jinja, use the template as a type, and call the outputs. For example:
imports: - path: example/path/to/mongodb.jinja name: mongodb.jinja resources: - name: my_mongo type: mongodb.jinja properties: size: 100 - name: my_instance type: compute.v1.instance properties: … databaseIp: $(ref.my_mongo.databaseIp) databasePort: $(ref.my_mongo.databasePort) Declaring an output
Declare an output in either a template or a configuration by defining an outputs: section at the same level as the resources: section. Output keys must be unique within the template or configuration.
For example, a sample outputs: section might look like this:
... outputs: - name: databaseIp value: $(ref.my-first-vm.networkInterfaces[0].accessConfigs[0].natIP) - name: machineType value: {{ properties['machineType'] }} - name: databasePort value: 88
Here's how the outputs might look in a full template:
Output values can be:
- A static string
- A reference to a property
- A template property
- An environment variable
Using outputs from templates
To use an output that has been defined in a template, import and use the template containing the output as a type. For example, to use outputs defined in a template called template_with_outputs.jinja, it must be imported and used to create a resource:
To call an output, use the following format:
$(ref.RESOURCE.OUTPUT) RESOURCEis the name of the resource created by the template. In the example above, this ismy-first-vm.OUTPUTis the output declared in the template. In the example above, this would bedatabaseIpanddatabasePort. This is the same syntax that you use to declare references. You can reference list items as well, for example:$ref.template.property[0].
When you deploy the configuration, Deployment Manager expands the configuration, and then replaces references to outputs with the output values.
Describing outputs in schemas
For templates that have accompanying schemas, you can describe output properties in further details. Deployment Manager does not enforce or validate any information in the outputs section but it is potentially helpful to use this section to provide more information about relevant outputs, for the benefit of users using your templates.
In your schema file, provide an outputs section that matches the output in your template. For example:
... outputs: databaseIp: description: Reference to ip address of your new cluster type: string databasePort: description: Port to talk on type: integer Users can reference your schema file to understand the usage and type of your outputs.
Looking up final output values
After you deploy templates that use outputs, view the final output values by viewing the configuration layout of the deployment. Final output values are indicated by the finalValue property. All output values are included in this field, including output values from nested templates. For example:
layout: | resources: - name: vm_template outputs: - finalValue: 104.197.69.69 name: databaseIp value: $(ref.vm-test.networkInterfaces[0].accessConfigs[0].natIP) properties: zone: us-central1-a resources: - name: datadisk-example-instance type: compute.v1.disk - name: vm-test type: compute.v1.instance type: vm_template.jinja name: manifest-1455057116997 Avoid circular dependencies
Be careful when creating templates where two or more resources rely on outputs from each other. Deployment Manager does not prevent this structure but if the outputs caused a circular dependency, the deployment won't deploy successfully. For example, the following snippet is accepted by Deployment Manager but if the contents of the templates causes a circular dependency, the deployment would fail:
resources: - name: frontend type: frontend.jinja properties: ip: $(ref.backend.ip) - name: backend type: backend.jinja properties: ip: $(ref.frontend.ip) As an example of a circular dependency where the deployment fails, assume both frontend.jinja and backend.jinja looked like this:
resources: - name: {{ env['name'] }} type: compute.v1.instance properties: zone: us-central1-f ... networkInterfaces: - network: global/networks/default accessConfigs: - name: External NAT type: ONE_TO_ONE_NAT metadata: items: - key: startup-script value: | #!/bin/bash export IP={{ properties["ip"] }} ... outputs: - name: ip value: $(ref.{{ env['name'] }}.networkInterfaces[0].accessConfigs[0].natIP)
Recall that both resources used the IP output property from the opposing resource:
resources: - name: frontend type: frontend.jinja properties: ip: $(ref.backend.ip) - name: backend type: backend.jinja properties: ip: $(ref.frontend.ip) But neither IP values can be populated because both properties rely on the existence of the other resource, creating a circular dependency. Here is the same template, fully expanded:
resources: - name: frontend type: compute.v1.instance properties: zone: us-central1-f ... networkInterfaces: - network: global/networks/default accessConfigs: - name: External NAT type: ONE_TO_ONE_NAT metadata: items: - key: startup-script value: | #!/bin/bash export IP=$(ref.backend.networkInterfaces[0].accessConfigs[0].natIP) - name: backend type: compute.v1.instance properties: zone: us-central1-f ... networkInterfaces: - network: global/networks/default accessConfigs: - name: External NAT type: ONE_TO_ONE_NAT metadata: items: - key: startup-script value: | #!/bin/bash export IP=$(ref.frontend.networkInterfaces[0].accessConfigs[0].natIP) Deployment Manager returns an error if you try to run configuration:
code: u'CONDITION_NOT_MET' message: u'A dependency cycle was found amongst backend, frontend.'>]> However, this template would work if:
- frontend.jinja created two virtual machine instances, vm-1 and vm-2.
- backend.jinja created vm-3 and vm-4.
- vm-1 exposed it's external IP as an output and vm-4 used that output.
- vm-3 exposed an external IP as an output, vm-2 used that output.
What's next
- Create a deployment.
- Learn more about templates.