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)
RESOURCE
is the name of the resource created by the template. In the example above, this ismy-first-vm
.OUTPUT
is the output declared in the template. In the example above, this would bedatabaseIp
anddatabasePort
. 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.