a8f6cc1f09
Change-Id: If71ad2579328d22430f56f81f3d35d220be734d5
720 lines
33 KiB
XML
720 lines
33 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="hot-software-deployment">
|
|
<!--WARNING: This file is automatically generated. Do not edit it.-->
|
|
<title>Software configuration</title>
|
|
<para>There are a variety of options to configure the software which runs on the
|
|
servers in your stack. These can be broadly divided into the following:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Custom image building</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>User-data boot scripts and cloud-init</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Software deployment resources</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>This section will describe each of these options and provide examples for
|
|
using them together in your stacks.</para>
|
|
<section xml:id="image-building">
|
|
<?dbhtml stop-chunking?>
|
|
<title>Image building</title>
|
|
<para>The first opportunity to influence what software is configured on your servers
|
|
is by booting them with a custom-built image. There are a number of reasons
|
|
you might want to do this, including:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis role="Boot speed"/> - since the required software is already on the image there
|
|
is no need to download and install anything at boot time.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><emphasis role="Boot reliability"/> - software downloads can fail for a number of reasons
|
|
including transient network failures and inconsistent software repositories.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><emphasis role="Test verification"/> - custom built images can be verified in test
|
|
environments before being promoted to production.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><emphasis role="Configuration dependencies"/> - post-boot configuration may depend on
|
|
agents already being installed and enabled</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>A number of tools are available for building custom images, including:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><link xlink:href="https://github.com/openstack/diskimage-builder">diskimage-builder</link> image building tools for OpenStack</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link xlink:href="http://imgfac.org/">imagefactory</link> builds images for a variety of operating system/cloud
|
|
combinations</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>Examples in this guide which require custom images will use <link xlink:href="https://github.com/openstack/diskimage-builder">diskimage-builder</link>.</para>
|
|
</section>
|
|
<section xml:id="user-data-boot-scripts-and-cloud-init">
|
|
<?dbhtml stop-chunking?>
|
|
<title>User-data boot scripts and cloud-init</title>
|
|
<para>When booting a server it is possible to specify the contents of the user-data
|
|
to be passed to that server. This user-data is made available either from
|
|
configured config-drive or from the <link xlink:href="http://docs.openstack.org/admin-guide-cloud/content/section_metadata-service.html">Metadata service</link>.</para>
|
|
<para>How this user-data is consumed depends on the image being booted, but the most
|
|
commonly used tool for default cloud images is <link xlink:href="http://cloudinit.readthedocs.org/en/latest/">Cloud-init</link>.</para>
|
|
<para>Whether the image is using <link xlink:href="http://cloudinit.readthedocs.org/en/latest/">Cloud-init</link> or not, it should be possible to
|
|
specify a shell script in the user_data property and have it be executed by
|
|
the server during boot:</para>
|
|
<programlisting language="yaml">resources:
|
|
|
|
the_server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data: |
|
|
#!/bin/bash
|
|
echo "Running boot script"
|
|
# ...</programlisting>
|
|
<!---->
|
|
<blockquote>
|
|
<para><emphasis role="Tip"/>: debugging these scripts it is often useful to view the boot
|
|
log using <literal>nova console-log <server-id></literal> to view the progress of boot
|
|
script execution.</para>
|
|
</blockquote>
|
|
<para>Often there is a need to set variable values based on parameters or resources
|
|
in the stack. This can be done with the <literal>str_replace</literal> intrinsic function:</para>
|
|
<programlisting language="yaml">parameters:
|
|
foo:
|
|
default: bar
|
|
|
|
resources:
|
|
|
|
the_server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data:
|
|
str_replace:
|
|
template: |
|
|
#!/bin/bash
|
|
echo "Running boot script with $FOO"
|
|
# ...
|
|
params:
|
|
$FOO: {get_param: foo}</programlisting>
|
|
<!---->
|
|
<blockquote>
|
|
<para><emphasis role="Warning"/>: If a stack-update is performed and there are any changes
|
|
at all to the content of user_data then the server will be replaced
|
|
(deleted and recreated) so that the modified boot configuration can be
|
|
run on a new server.</para>
|
|
</blockquote>
|
|
<para>When these scripts grow it can become difficult to maintain them inside the
|
|
template, so the <literal>get_file</literal> intrinsic function can be used to maintain the
|
|
script in a separate file:</para>
|
|
<programlisting language="yaml">parameters:
|
|
foo:
|
|
default: bar
|
|
|
|
resources:
|
|
|
|
the_server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data:
|
|
str_replace:
|
|
template: {get_file: the_server_boot.sh}
|
|
params:
|
|
$FOO: {get_param: foo}</programlisting>
|
|
<!---->
|
|
<blockquote>
|
|
<para><emphasis role="Tip"/>: <literal>str_replace</literal> can replace any strings, not just strings
|
|
starting with <literal>$</literal>. However doing this for the above example is useful
|
|
because the script file can be executed for testing by passing in
|
|
environment variables.</para>
|
|
</blockquote>
|
|
<section xml:id="choosing-the-user-data-format">
|
|
<title>Choosing the user_data_format</title>
|
|
<para>The <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Nova__Server.html">OS::Nova::Server</link></literal> user_data_format property determines how the
|
|
user_data should be formatted for the server. For the default value
|
|
<literal>HEAT_CFNTOOLS</literal>, the user_data is bundled as part of the heat-cfntools
|
|
cloud-init boot configuration data. While <literal>HEAT_CFNTOOLS</literal> is the default
|
|
for <literal>user_data_format</literal>, it is considered legacy and <literal>RAW</literal> or
|
|
<literal>SOFTWARE_CONFIG</literal> will generally be more appropriate.</para>
|
|
<para>For <literal>RAW</literal> the user_data is passed to Nova unmodified. For a <link xlink:href="http://cloudinit.readthedocs.org/en/latest/">Cloud-init</link>
|
|
enabled image, the following are both valid <literal>RAW</literal> user-data:</para>
|
|
<programlisting language="yaml">resources:
|
|
|
|
server_with_boot_script:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data: |
|
|
#!/bin/bash
|
|
echo "Running boot script"
|
|
# ...
|
|
|
|
server_with_cloud_config:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data: |
|
|
#cloud-config
|
|
final_message: "The system is finally up, after $UPTIME seconds"</programlisting>
|
|
<para>For <literal>SOFTWARE_CONFIG</literal> user_data is bundled as part of the software config
|
|
data, and metadata is derived from any associated
|
|
<link linkend="software-deployment-resources">Software deployment resources</link>.</para>
|
|
</section>
|
|
<section xml:id="signals-and-wait-conditions">
|
|
<title>Signals and wait conditions</title>
|
|
<para>Often it is necessary to pause further creation of stack resources until the
|
|
boot configuration script has notified that it has reached a certain state.
|
|
This is usually either to notify that a service is now active, or to pass out
|
|
some generated data which is needed by another resource. The resources
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__WaitCondition.html">OS::Heat::WaitCondition</link></literal> and <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SwiftSignal.html">OS::Heat::SwiftSignal</link></literal> both perform
|
|
this function using different techniques and tradeoffs.</para>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__WaitCondition.html">OS::Heat::WaitCondition</link></literal> is implemented as a call to the
|
|
<link xlink:href="http://developer.openstack.org/api-ref-orchestration-v1.html">Orchestration API</link> resource signal. The token is created using credentials
|
|
for a user account which is scoped only to the wait condition handle
|
|
resource. This user is created when the handle is created, and is associated
|
|
to a project which belongs to the stack, in an identity domain which is
|
|
dedicated to the orchestration service.</para>
|
|
<para>Sending the signal is a simple HTTP request, as with this example using <link xlink:href="http://curl.haxx.se/">curl</link>:</para>
|
|
<programlisting language="sh">curl -i -X POST -H 'X-Auth-Token: <token>' \
|
|
-H 'Content-Type: application/json' -H 'Accept: application/json' \
|
|
'<wait condition URL>' --data-binary '<json containing signal data>'</programlisting>
|
|
<para>The JSON containing the signal data is expected to be of the following format:</para>
|
|
<programlisting language="json">{
|
|
"status": "SUCCESS",
|
|
"reason": "The reason which will appear in the 'heat event-list' output",
|
|
"data": "Data to be used elsewhere in the template via get_attr",
|
|
"id": "Optional unique ID of signal"
|
|
}</programlisting>
|
|
<para>All of these values are optional, and if not specified will be set to the
|
|
following defaults:</para>
|
|
<programlisting language="json">{
|
|
"status": "SUCCESS",
|
|
"reason": "Signal <id> received",
|
|
"data": null,
|
|
"id": "<sequential number starting from 1 for each signal received>"
|
|
}</programlisting>
|
|
<para>If <literal>status</literal> is set to <literal>FAILURE</literal> then the resource (and the stack) will go
|
|
into a <literal>FAILED</literal> state using the <literal>reason</literal> as failure reason.</para>
|
|
<para>The following template example uses the convenience attribute <literal>curl_cli</literal>
|
|
which builds a curl command with a valid token:</para>
|
|
<programlisting language="yaml">resources:
|
|
wait_condition:
|
|
type: OS::Heat::WaitCondition
|
|
properties:
|
|
handle: {get_resource: wait_handle}
|
|
# Note, count of 5 vs 6 is due to duplicate signal ID 5 sent below
|
|
count: 5
|
|
timeout: 300
|
|
|
|
wait_handle:
|
|
type: OS::Heat::WaitConditionHandle
|
|
|
|
the_server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data:
|
|
str_replace:
|
|
template: |
|
|
#!/bin/sh
|
|
# Below are some examples of the various ways signals
|
|
# can be sent to the Handle resource
|
|
|
|
# Simple success signal
|
|
wc_notify --data-binary '{"status": "SUCCESS"}'
|
|
|
|
# Or you optionally can specify any of the additional fields
|
|
wc_notify --data-binary '{"status": "SUCCESS", "reason": "signal2"}'
|
|
wc_notify --data-binary '{"status": "SUCCESS", "reason": "signal3", "data": "data3"}'
|
|
wc_notify --data-binary '{"status": "SUCCESS", "reason": "signal4", "data": "data4"}'
|
|
|
|
# If you require control of the ID, you can pass it.
|
|
# The ID should be unique, unless you intend for duplicate
|
|
# signals to overrite each other. The following two calls
|
|
# do the exact same thing, and will be treated as one signal
|
|
# (You can prove this by changing count above to 7)
|
|
wc_notify --data-binary '{"status": "SUCCESS", "id": "5"}'
|
|
wc_notify --data-binary '{"status": "SUCCESS", "id": "5"}'
|
|
|
|
# Example of sending a failure signal, optionally
|
|
# reason, id, and data can be specified as above
|
|
# wc_notify --data-binary '{"status": "FAILURE"}'
|
|
params:
|
|
wc_notify: { get_attr: [wait_handle, curl_cli] }
|
|
|
|
outputs:
|
|
wc_data:
|
|
value: { get_attr: [wait_condition, data] }
|
|
# this would return the following json
|
|
# {"1": null, "2": null, "3": "data3", "4": "data4", "5": null}
|
|
|
|
wc_data_4:
|
|
value: { get_attr: [wait_condition, data, '4'] }
|
|
# this would return "data4"</programlisting>
|
|
<!---->
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SwiftSignal.html">OS::Heat::SwiftSignal</link></literal> is implemented by creating an Object Storage
|
|
API temporary URL which is populated with signal data with an HTTP PUT. The
|
|
orchestration service will poll this object until the signal data is available.
|
|
Object versioning is used to store multiple signals.</para>
|
|
<para>Sending the signal is a simple HTTP request, as with this example using <link xlink:href="http://curl.haxx.se/">curl</link>:</para>
|
|
<programlisting language="sh">curl -i -X PUT '<object URL>' --data-binary '<json containing signal data>'</programlisting>
|
|
<para>The above template example only needs to have the <literal>type</literal> changed to the
|
|
swift signal resources:</para>
|
|
<programlisting language="yaml">resources:
|
|
signal:
|
|
type: OS::Heat::SwiftSignal
|
|
properties:
|
|
handle: {get_resource: wait_handle}
|
|
timeout: 300
|
|
|
|
signal_handle:
|
|
type: OS::Heat::SwiftSignalHandle
|
|
# ...</programlisting>
|
|
<para>The decision to use <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__WaitCondition.html">OS::Heat::WaitCondition</link></literal> or
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SwiftSignal.html">OS::Heat::SwiftSignal</link></literal> will depend on a few factors:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SwiftSignal.html">OS::Heat::SwiftSignal</link></literal> depends on the availability of an Object
|
|
Storage API</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__WaitCondition.html">OS::Heat::WaitCondition</link></literal> depends on whether the orchestration
|
|
service has been configured with a dedicated stack domain (which may depend
|
|
on the availability of an Identity V3 API).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The preference to protect signal URLs with token authentication or a
|
|
secret webhook URL.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section xml:id="software-config-resources">
|
|
<title>Software config resources</title>
|
|
<para>Boot configuration scripts can also be managed as their own resources. This
|
|
allows configuration to be defined once and run on multiple server resources.
|
|
These software-config resources are stored and retrieved via dedicated calls
|
|
to the <link xlink:href="http://developer.openstack.org/api-ref-orchestration-v1.html">Orchestration API</link>. It is not possible to modify the contents of an
|
|
existing software-config resource, so a stack-update which changes any
|
|
existing software-config resource will result in API calls to create a new
|
|
config and delete the old one.</para>
|
|
<para>The resource <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> is used for storing configs
|
|
represented by text scripts, for example:</para>
|
|
<programlisting language="yaml">resources:
|
|
boot_script:
|
|
type: OS::Heat::SoftwareConfig
|
|
properties:
|
|
group: ungrouped
|
|
config: |
|
|
#!/bin/bash
|
|
echo "Running boot script"
|
|
# ...
|
|
|
|
server_with_boot_script:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data: {get_resource: boot_script}</programlisting>
|
|
<para>The resource <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__CloudConfig.html">OS::Heat::CloudConfig</link></literal> allows <link xlink:href="http://cloudinit.readthedocs.org/en/latest/">Cloud-init</link> cloud-config to
|
|
be represented as template YAML rather than a block string. This allows
|
|
intrinsic functions to be included when building the cloud-config. This also
|
|
ensures that the cloud-config is valid YAML, although no further checks for
|
|
valid cloud-config are done.</para>
|
|
<programlisting language="yaml">parameters:
|
|
file_content:
|
|
type: string
|
|
description: The contents of the file /tmp/file
|
|
|
|
resources:
|
|
boot_config:
|
|
type: OS::Heat::CloudConfig
|
|
properties:
|
|
cloud_config:
|
|
write_files:
|
|
- path: /tmp/file
|
|
content: {get_param: file_content}
|
|
|
|
server_with_cloud_config:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data: {get_resource: boot_config}</programlisting>
|
|
<!---->
|
|
<para>The resource <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__MultipartMime.html">OS::Heat::MultipartMime</link></literal> allows multiple
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> and <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__CloudConfig.html">OS::Heat::CloudConfig</link></literal>
|
|
resources to be combined into a single <link xlink:href="http://cloudinit.readthedocs.org/en/latest/">Cloud-init</link> multi-part message:</para>
|
|
<programlisting language="yaml">parameters:
|
|
file_content:
|
|
type: string
|
|
description: The contents of the file /tmp/file
|
|
|
|
other_config:
|
|
type: string
|
|
description: The ID of a software-config resource created elsewhere
|
|
|
|
resources:
|
|
boot_config:
|
|
type: OS::Heat::CloudConfig
|
|
properties:
|
|
cloud_config:
|
|
write_files:
|
|
- path: /tmp/file
|
|
content: {get_param: file_content}
|
|
|
|
boot_script:
|
|
type: OS::Heat::SoftwareConfig
|
|
properties:
|
|
group: ungrouped
|
|
config: |
|
|
#!/bin/bash
|
|
echo "Running boot script"
|
|
# ...
|
|
|
|
server_init:
|
|
type: OS::Heat::MultipartMime
|
|
properties:
|
|
parts:
|
|
- config: {get_resource: boot_config}
|
|
- config: {get_resource: boot_script}
|
|
- config: {get_resource: other_config}
|
|
|
|
server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: RAW
|
|
user_data: {get_resource: server_init}</programlisting>
|
|
<!---->
|
|
</section>
|
|
</section>
|
|
<section xml:id="software-deployment-resources">
|
|
<?dbhtml stop-chunking?>
|
|
<title>Software deployment resources</title>
|
|
<para>There are many situations where it is not desirable to replace the server
|
|
whenever there is a configuration change. The
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareDeployment.html">OS::Heat::SoftwareDeployment</link></literal> resource allows any number of software
|
|
configurations to be added or removed from a server throughout its life-cycle.</para>
|
|
<section xml:id="building-custom-image-for-software-deployments">
|
|
<title>Building custom image for software deployments</title>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> resources are used to store software
|
|
configuration, and a <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareDeployment.html">OS::Heat::SoftwareDeployment</link></literal> resource is used
|
|
to associate a config resource with one server. The <literal>group</literal> attribute on
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> specifies what tool will consume the
|
|
config content.</para>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> has the ability to define a schema of
|
|
<literal>inputs</literal> and which the configuration script supports. Inputs are mapped to
|
|
whatever concept the configuration tool has for assigning
|
|
variables/parameters.</para>
|
|
<para>Likewise, <literal>outputs</literal> are mapped to the tool's capability to export structured
|
|
data after configuration execution. For tools which do not support this,
|
|
outputs can always be written to a known file path for the hook to read.</para>
|
|
<para>The <literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareDeployment.html">OS::Heat::SoftwareDeployment</link></literal> resource allows values to be
|
|
assigned to the config inputs, and the resource remains in an <literal>IN_PROGRESS</literal>
|
|
state until the server signals to heat what (if any) output values were
|
|
generated by the config script.</para>
|
|
</section>
|
|
<section xml:id="custom-image-script">
|
|
<title>Custom image script</title>
|
|
<para>Each of the following examples requires that the servers be booted with a
|
|
custom image. The following script uses diskimage-builder to create an image
|
|
required in later examples:</para>
|
|
<programlisting language="sh"># Clone the required repositories. Some of these are also available
|
|
# via pypi or as distro packages.
|
|
git clone https://git.openstack.org/openstack/diskimage-builder.git
|
|
git clone https://git.openstack.org/openstack/tripleo-image-elements.git
|
|
git clone https://git.openstack.org/openstack/heat-templates.git
|
|
|
|
# Required by diskimage-builder to discover element collections
|
|
export ELEMENTS_PATH=tripleo-image-elements/elements:heat-templates/hot/software-config/elements
|
|
|
|
# The base operating system element(s) provided by the diskimage-builder
|
|
# elements collection. Other values which may work include:
|
|
# centos7, debian, opensuse, rhel, rhel7, or ubuntu
|
|
export BASE_ELEMENTS="fedora selinux-permissive"
|
|
# Install and configure the os-collect-config agent to poll the heat service
|
|
# for configuration changes to execute
|
|
export AGENT_ELEMENTS="os-collect-config os-refresh-config os-apply-config"
|
|
|
|
|
|
# heat-config installs an os-refresh-config script which will invoke the
|
|
# appropriate hook to perform configuration. The element heat-config-script
|
|
# installs a hook to perform configuration with shell scripts
|
|
export DEPLOYMENT_BASE_ELEMENTS="heat-config heat-config-script"
|
|
|
|
# Install a hook for any other chosen configuration tool(s).
|
|
# Elements which install hooks include:
|
|
# heat-config-cfn-init, heat-config-puppet, or heat-config-salt
|
|
export DEPLOYMENT_TOOL=""
|
|
|
|
# The name of the qcow2 image to create, and the name of the image
|
|
# uploaded to the OpenStack image registry.
|
|
export IMAGE_NAME=fedora-software-config
|
|
|
|
# Create the image
|
|
diskimage-builder/bin/disk-image-create vm $BASE_ELEMENTS $AGENT_ELEMENTS \
|
|
$DEPLOYMENT_BASE_ELEMENTS $DEPLOYMENT_TOOL -o $IMAGE_NAME.qcow2
|
|
|
|
# Upload the image, assuming valid credentials are already sourced
|
|
glance image-create --disk-format qcow2 --container-format bare \
|
|
--name $IMAGE_NAME < $IMAGE_NAME.qcow2</programlisting>
|
|
<!---->
|
|
</section>
|
|
<section xml:id="configuring-with-scripts">
|
|
<title>Configuring with scripts</title>
|
|
<para>The <link linkend="custom-image-script">Custom image script</link> already includes the <literal>heat-config-script</literal> element
|
|
so the built image will already have the ability to configure using shell
|
|
scripts.</para>
|
|
<para>Config inputs are mapped to shell environment variables. The script can
|
|
communicate outputs to heat by writing to the file
|
|
<literal>$heat_outputs_path.<output name></literal>. See the following example for a script
|
|
which expects inputs <literal>foo</literal>, <literal>bar</literal> and generates an output <literal>result</literal>.</para>
|
|
<programlisting language="yaml">resources:
|
|
config:
|
|
type: OS::Heat::SoftwareConfig
|
|
properties:
|
|
group: script
|
|
inputs:
|
|
- name: foo
|
|
- name: bar
|
|
outputs:
|
|
- name: result
|
|
config: |
|
|
#!/bin/sh -x
|
|
echo "Writing to /tmp/$bar"
|
|
echo $foo > /tmp/$bar
|
|
echo -n "The file /tmp/$bar contains `cat /tmp/$bar` for server $deploy_server_id during $deploy_action" > $heat_outputs_path.result
|
|
echo "Written to /tmp/$bar"
|
|
echo "Output to stderr" 1>&2
|
|
|
|
deployment:
|
|
type: OS::Heat::SoftwareDeployment
|
|
properties:
|
|
config:
|
|
get_resource: config
|
|
server:
|
|
get_resource: server
|
|
input_values:
|
|
foo: fooooo
|
|
bar: baaaaa
|
|
|
|
server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
# flavor, image etc
|
|
user_data_format: SOFTWARE_CONFIG
|
|
|
|
outputs:
|
|
result:
|
|
value:
|
|
get_attr: [deployment, result]
|
|
stdout:
|
|
value:
|
|
get_attr: [deployment, deploy_stdout]
|
|
stderr:
|
|
value:
|
|
get_attr: [deployment, deploy_stderr]
|
|
status_code:
|
|
value:
|
|
get_attr: [deployment, deploy_status_code]</programlisting>
|
|
<!---->
|
|
<blockquote>
|
|
<para><emphasis role="Tip"/>: A config resource can be associated with multiple deployment
|
|
resources, and each deployment can specify the same or different values
|
|
for the <literal>server</literal> and <literal>input_values</literal> properties.</para>
|
|
</blockquote>
|
|
<para>As can be seen in the <literal>outputs</literal> section of the above template, the
|
|
<literal>result</literal> config output value is available as an attribute on the
|
|
<literal>deployment</literal> resource. Likewise the captured stdout, stderr and status_code
|
|
are also available as attributes.</para>
|
|
</section>
|
|
<section xml:id="configuring-with-os-apply-config">
|
|
<title>Configuring with os-apply-config</title>
|
|
<para>The agent toolchain of <literal>os-collect-config</literal>, <literal>os-refresh-config</literal> and
|
|
<literal>os-apply-config</literal> can actually be used on their own to inject heat stack
|
|
configuration data into a server running a custom image.</para>
|
|
<para>The custom image needs to have the following to use this approach:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>All software dependencies installed</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link xlink:href="https://github.com/openstack/os-refresh-config">os-refresh-config</link> scripts to be executed on configuration changes</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link xlink:href="https://github.com/openstack/os-apply-config">os-apply-config</link> templates to transform the heat-provided config data into
|
|
service configuration files</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>The projects <link xlink:href="https://github.com/openstack/tripleo-image-elements">tripleo-image-elements</link> and <link xlink:href="https://github.com/openstack/tripleo-heat-templates">tripleo-heat-templates</link> demonstrate
|
|
this approach.</para>
|
|
</section>
|
|
<section xml:id="configuring-with-cfn-init">
|
|
<title>Configuring with cfn-init</title>
|
|
<para>Likely the only reason to use the <literal>cfn-init</literal> hook is to migrate templates
|
|
which contain <link xlink:href="http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html">AWS::CloudFormation::Init</link> metadata without needing a
|
|
complete rewrite of the config metadata. It is included here as it introduces
|
|
a number of new concepts.</para>
|
|
<para>To use the <literal>cfn-init</literal> tool the <literal>heat-config-cfn-init</literal> element is required
|
|
to be on the built image, so <link linkend="custom-image-script">Custom image script</link> needs to be modified with
|
|
the following:</para>
|
|
<programlisting language="sh">export DEPLOYMENT_TOOL="heat-config-cfn-init"</programlisting>
|
|
<!---->
|
|
<para>Configuration data which used to be included in the
|
|
<literal>AWS::CloudFormation::Init</literal> section of resource metadata is instead moved
|
|
to the <literal>config</literal> property of the config resource, as in the following
|
|
example:</para>
|
|
<programlisting language="yaml">resources:
|
|
|
|
config:
|
|
type: OS::Heat::StructuredConfig
|
|
properties:
|
|
group: cfn-init
|
|
inputs:
|
|
- name: bar
|
|
config:
|
|
config:
|
|
files:
|
|
/tmp/foo:
|
|
content:
|
|
get_input: bar
|
|
mode: '000644'
|
|
|
|
deployment:
|
|
type: OS::Heat::StructuredDeployment
|
|
properties:
|
|
name: 10_deployment
|
|
signal_transport: NO_SIGNAL
|
|
config:
|
|
get_resource: config
|
|
server:
|
|
get_resource: server
|
|
input_values:
|
|
bar: baaaaa
|
|
|
|
other_deployment:
|
|
type: OS::Heat::StructuredDeployment
|
|
properties:
|
|
name: 20_other_deployment
|
|
signal_transport: NO_SIGNAL
|
|
config:
|
|
get_resource: config
|
|
server:
|
|
get_resource: server
|
|
input_values:
|
|
bar: barmy
|
|
|
|
server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
image: {get_param: image}
|
|
flavor: {get_param: flavor}
|
|
key_name: {get_param: key_name}
|
|
user_data_format: SOFTWARE_CONFIG</programlisting>
|
|
<!---->
|
|
<para>There are a number of things to note about this template example:</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__StructuredConfig.html">OS::Heat::StructuredConfig</link></literal> is like
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__SoftwareConfig.html">OS::Heat::SoftwareConfig</link></literal> except that the <literal>config</literal> property
|
|
contains structured YAML instead of text script. This is useful for a
|
|
number of other configuration tools including ansible, salt and
|
|
os-apply-config.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal>cfn-init</literal> has no concept of inputs, so <literal>{get_input: bar}</literal> acts as a
|
|
placeholder which gets replaced with the
|
|
<literal><link xlink:href="http://docs.openstack.org/hot-reference/content/OS__Heat__StructuredDeployment.html">OS::Heat::StructuredDeployment</link></literal><literal>input_values</literal> value when the
|
|
deployment resource is created.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><literal>cfn-init</literal> has no concept of outputs, so specifying
|
|
<literal>signal_transport: NO_SIGNAL</literal> will mean that the deployment resource will
|
|
immediately go into the <literal>CREATED</literal> state instead of waiting for a
|
|
completed signal from the server.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The template has 2 deployment resources deploying the same config with
|
|
different <literal>input_values</literal>. The order these are deployed in on the server
|
|
is determined by sorting the values of the <literal>name</literal> property for each
|
|
resource (10_deployment, 20_other_deployment)</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section xml:id="configuring-with-puppet">
|
|
<title>Configuring with puppet</title>
|
|
<para>The <link xlink:href="http://puppetlabs.com/">puppet</link> hook makes it possible to write configuration as puppet manifests
|
|
which are deployed and run in a masterless environment.</para>
|
|
<para>To specify configuration as puppet manifests the <literal>heat-config-puppet</literal>
|
|
element is required to be on the built image, so <link linkend="custom-image-script">Custom image script</link> needs
|
|
to be modified with the following:</para>
|
|
<programlisting language="sh">export DEPLOYMENT_TOOL="heat-config-puppet"</programlisting>
|
|
<!---->
|
|
<programlisting language="yaml">resources:
|
|
|
|
config:
|
|
type: OS::Heat::SoftwareConfig
|
|
properties:
|
|
group: puppet
|
|
inputs:
|
|
- name: foo
|
|
- name: bar
|
|
outputs:
|
|
- name: result
|
|
config:
|
|
get_file: example-puppet-manifest.pp
|
|
|
|
deployment:
|
|
type: OS::Heat::SoftwareDeployment
|
|
properties:
|
|
config:
|
|
get_resource: config
|
|
server:
|
|
get_resource: server
|
|
input_values:
|
|
foo: fooooo
|
|
bar: baaaaa
|
|
|
|
server:
|
|
type: OS::Nova::Server
|
|
properties:
|
|
image: {get_param: image}
|
|
flavor: {get_param: flavor}
|
|
key_name: {get_param: key_name}
|
|
user_data_format: SOFTWARE_CONFIG
|
|
|
|
outputs:
|
|
result:
|
|
value:
|
|
get_attr: [deployment, result]
|
|
stdout:
|
|
value:
|
|
get_attr: [deployment, deploy_stdout]</programlisting>
|
|
<!---->
|
|
<para>This demonstrates the use of the <literal>get_file</literal> function, which will attach the
|
|
contents of the file <literal>example-puppet-manifest.pp</literal>, containing:</para>
|
|
<programlisting language="puppet">file { 'barfile':
|
|
ensure => file,
|
|
mode => '0644',
|
|
path => '/tmp/$::bar',
|
|
content => '$::foo',
|
|
}
|
|
|
|
file { 'output_result':
|
|
ensure => file,
|
|
path => '$::heat_outputs_path.result',
|
|
mode => '0644',
|
|
content => 'The file /tmp/$::bar contains $::foo',
|
|
}</programlisting>
|
|
<!---->
|
|
</section>
|
|
</section>
|
|
</section>
|