Initial input for HOT template guide and spec
This patch adds initial input for the HOT template guide and the HOT specification. Note that content so far is based on features implemented so far and not forward-looking in any way. Whenever new features get implemented, the guide and spec will be extended appropriately. Contributes to blueprint hot-specification Change-Id: I63d29ab0a1db6703b39f981161063d4fd9f97126
This commit is contained in:
parent
f6b6cf8097
commit
514e9b746c
221
doc/source/template_guide/hot_guide.rst
Normal file
221
doc/source/template_guide/hot_guide.rst
Normal file
@ -0,0 +1,221 @@
|
||||
..
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
=======================================
|
||||
Heat Orchestration Template (HOT) Guide
|
||||
=======================================
|
||||
|
||||
HOT is a new template format meant to replace the Heat CloudFormation-compatible
|
||||
format (CFN) as the native format supported by the Heat over time.
|
||||
This guide is targeted towards template authors and explains how to write
|
||||
HOT templates based on examples. A detailed specification of HOT can be found
|
||||
at :ref:`_hot_spec`.
|
||||
|
||||
------
|
||||
Status
|
||||
------
|
||||
|
||||
HOT support is still under development and needs more work to provide access to
|
||||
all functionality currently available via the CFN compatible template interface.
|
||||
This guide will be updated periodically whenever new features get implemented
|
||||
for HOT.
|
||||
|
||||
----------------------------------
|
||||
Writing a hello world HOT template
|
||||
----------------------------------
|
||||
|
||||
This section gives an introduction on how to write HOT templates, starting from
|
||||
very basic steps and then going into more and more detail by means of examples.
|
||||
|
||||
A most basic template
|
||||
---------------------
|
||||
The most basic template you can think of may contain only a single resource
|
||||
definition using only predefined properties (along with the mandatory Heat
|
||||
template version tag). For example, the template below could be used to simply
|
||||
deploy a single compute instance.
|
||||
|
||||
::
|
||||
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: Simple template to deploy a single compute instance
|
||||
|
||||
resources:
|
||||
my_instance:
|
||||
type: OS::Nova::Compute
|
||||
properties:
|
||||
KeyName: my_key
|
||||
ImageId: F18-x86_64-cfntools
|
||||
InstanceType: m1.small
|
||||
|
||||
Each HOT template has to include the *heat_template_version* key with value
|
||||
'2013-05-23' (the current version of HOT). While the *description* is optional,
|
||||
it is good practice to include some useful text that describes what users can do
|
||||
with the template. In case you want to provide a longer description that does
|
||||
not fit on a single line, you can provide multi-line text in YAML, for example:
|
||||
|
||||
::
|
||||
|
||||
description: >
|
||||
This is how you can provide a longer description
|
||||
of your template that goes over several lines.
|
||||
|
||||
The *resources* section is required and must contain at least one resource
|
||||
definition. In the example above, a compute instance is defined with fixed
|
||||
values for the 'KeyName', 'ImageId' and 'InstanceType' parameters.
|
||||
|
||||
Note that all those elements, i.e. a key-pair with the given name, the image and
|
||||
the flavor have to exist in the OpenStack environment where the template is
|
||||
used. Typically a template is made more easily reusable, though, by defining a
|
||||
set of *input parameters* instead of hard-coding such values.
|
||||
|
||||
|
||||
Template input parameters
|
||||
-------------------------
|
||||
Input parameters defined in the *parameters* section of a HOT template (see also
|
||||
:ref:`_hot_spec_parameters`) allow users to customize a template during
|
||||
deployment. For example, this allows for providing custom key-pair names or
|
||||
image IDs to be used for a deployment.
|
||||
From a template author's perspective, this helps to make a template more easily
|
||||
reusable by avoiding hardcoded assumptions.
|
||||
|
||||
Sticking to the example used above, it makes sense to allow users to provide
|
||||
their custom key-pairs, provide their own image, and to select a flavor for the
|
||||
compute instance. This can be achieved by extending the initial template as
|
||||
follows:
|
||||
|
||||
::
|
||||
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: Simple template to deploy a single compute instance
|
||||
|
||||
parameters:
|
||||
key_name:
|
||||
type: string
|
||||
description: Name of key-pair to be used for compute instance
|
||||
image_id:
|
||||
type: string
|
||||
description: Image to be used for compute instance
|
||||
instance_type:
|
||||
type: string
|
||||
description: Type of instance (flavor) to be used
|
||||
|
||||
resources:
|
||||
my_instance:
|
||||
type: OS::Nova::Compute
|
||||
properties:
|
||||
KeyName: { get_param: key_name }
|
||||
ImageId: { get_param: image_id }
|
||||
InstanceType: { get_param: instance_type }
|
||||
|
||||
In the example above, three input parameters have been defined that have to be
|
||||
provided by the user upon deployment. The fixed values for the respective
|
||||
resource properties have been replaced by references to the corresponding
|
||||
input parameters by means of the *get_param* function (see also
|
||||
:ref:`_hot_spec_intrinsic_functions`).
|
||||
|
||||
You can also define default values for input parameters which will be used in
|
||||
case the user does not provide the respective parameter during deployment. For
|
||||
example, the following definition for the *instance_type* parameter would select
|
||||
the 'm1.small' flavor unless specified otherwise be the user.
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
instance_type:
|
||||
type: string
|
||||
description: Type of instance (flavor) to be used
|
||||
default: m1.small
|
||||
|
||||
Another option that can be specified for a parameter is to hide its value when
|
||||
users request information about a stack deployed from a template. This is
|
||||
achieved by the *hidden* attribute and useful, for example when requesting
|
||||
passwords as user input:
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
database_password:
|
||||
type: string
|
||||
description: Password to be used for database
|
||||
hidden: true
|
||||
|
||||
|
||||
Restricting user input
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
In some cases you might want to restrict the values of input parameters that
|
||||
users can supply. For example, you might know that the software running in a
|
||||
compute instance needs a certain amount of resources so you might want to
|
||||
restrict the *instance_type* parameter introduced above. Parameters in HOT
|
||||
templates can be restricted by adding a *constraints* section (see also
|
||||
:ref:`_hot_spec_parameters_constraints`).
|
||||
For example, the following would allow only three values to be provided as input
|
||||
for the *instance_type* parameter:
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
instance_type:
|
||||
type: string
|
||||
description: Type of instance (flavor) to be used
|
||||
constraints:
|
||||
- allow_values: [ m1.medium, m1.large, m1.xlarge ]
|
||||
description: Value must be one of m1.medium, m1.large or m1.xlarge.
|
||||
|
||||
The *constraints* section allows for defining a list of constraints that must
|
||||
all be fulfilled by user input. For example, the following list of constraints
|
||||
could be used to clearly specify format requirements on a password to be
|
||||
provided by users:
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
database_password:
|
||||
type: string
|
||||
description: Password to be used for database
|
||||
hidden: true
|
||||
constraints:
|
||||
- length: { min: 6, max: 8 }
|
||||
description: Password length must be between 6 and 8 characters.
|
||||
- allowed_pattern: "[a-zA-Z0-9]+"
|
||||
description: Password must consist of characters and numbers only.
|
||||
- allowed_pattern: "[A-Z]+[a-zA-Z0-9]*"
|
||||
description: Password must start with an uppercase character.
|
||||
|
||||
Note that you can define multiple constraints of the same type. Especially in
|
||||
the case of allowed patterns this not only allows for keeping regular
|
||||
expressions simple and maintainable, but also for keeping error messages to be
|
||||
presented to users precise.
|
||||
|
||||
|
||||
Providing template outputs
|
||||
--------------------------
|
||||
In addition to template customization through input parameters, you will
|
||||
typically want to provide outputs to users, which can be done in the
|
||||
*outputs* section of a template (see also :ref:`_hot_spec_outputs`).
|
||||
For example, the IP address by which the instance defined in the example
|
||||
above can be accessed should be provided to users. Otherwise, users would have
|
||||
to look it up themselves. The definition for providing the IP address of the
|
||||
compute instance as an output is shown in the following snippet:
|
||||
|
||||
::
|
||||
|
||||
outputs:
|
||||
instance_ip:
|
||||
description: The IP address of the deployed instance
|
||||
value: { get_attr: [my_instance, PublicIp] }
|
||||
|
||||
Output values are typically resolved using intrinsic function such as
|
||||
the *get_attr* function in the example above (see also
|
||||
:ref:`_hot_spec_intrinsic_functions`).
|
444
doc/source/template_guide/hot_spec.rst
Normal file
444
doc/source/template_guide/hot_spec.rst
Normal file
@ -0,0 +1,444 @@
|
||||
..
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
.. _hot_spec:
|
||||
|
||||
===============================================
|
||||
Heat Orchestration Template (HOT) Specification
|
||||
===============================================
|
||||
|
||||
HOT is a new template format meant to replace the Heat CloudFormation-compatible
|
||||
format (CFN) as the native format supported by the Heat over time.
|
||||
This specification explains in detail all elements of the HOT template format.
|
||||
An example driven guide to writing HOT templates can be found
|
||||
at :ref:`_hot_guide`.
|
||||
|
||||
------
|
||||
Status
|
||||
------
|
||||
|
||||
HOT support is still under development and needs more work to provide access to
|
||||
all functionality currently available via the CFN compatible template interface.
|
||||
This specification will be updated periodically whenever new features get
|
||||
implemented for HOT.
|
||||
|
||||
------------------
|
||||
Template Structure
|
||||
------------------
|
||||
|
||||
HOT templates are defined in YAML and follow the structure outlined below.
|
||||
|
||||
::
|
||||
|
||||
heat_template_version: 2013-05-23
|
||||
|
||||
description: # a description of the template
|
||||
|
||||
parameters:
|
||||
# declaration of input parameters
|
||||
|
||||
resources:
|
||||
# declaration of template resources
|
||||
|
||||
outputs:
|
||||
# declaration of output parameters
|
||||
|
||||
heat_template_version
|
||||
This key with value *2013-05-23* (or a later date) indicates that the YAML
|
||||
document is a HOT template of the specified version.
|
||||
|
||||
description
|
||||
This *optional* key allows for giving a description of the template, or the
|
||||
workload that can be deployed using the template.
|
||||
|
||||
parameters
|
||||
This section allows for specifying input parameters that have to be provided
|
||||
when instantiating the template. The section is *optional* and can be
|
||||
omitted when no input is required.
|
||||
|
||||
resources
|
||||
This section contains the declaration of the single resources of the
|
||||
template. This section is mandatory and at least one resource must be
|
||||
defined in any HOT template.
|
||||
|
||||
outputs
|
||||
This section allows for specifying output parameters available to users once
|
||||
the template has been instantiated. This section is *optional* and can be
|
||||
omitted when no output values are required.
|
||||
|
||||
|
||||
.. _hot_spec_parameters:
|
||||
|
||||
------------------
|
||||
Parameters Section
|
||||
------------------
|
||||
|
||||
The *parameters* section allows for specifying input parameters that have to be
|
||||
provided when instantiating the template. Such parameters are typically used to
|
||||
customize each deployment (e.g. by setting custom user names or passwords) or
|
||||
for binding to environment-specifics like certain images.
|
||||
|
||||
Each parameter is specified in a separated nested block with the name of the
|
||||
parameters defined in the first line and additional attributes such as type or
|
||||
default value defined as nested elements.
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
<param name>:
|
||||
type: <string | number | json | comma_delimited_list>
|
||||
description: <description of the parameter>
|
||||
default: <default value for parameter>
|
||||
hidden: <true | false>
|
||||
constraints:
|
||||
<parameter constraints>
|
||||
|
||||
param name
|
||||
The name of the parameter is defined at the top of each parameter block.
|
||||
|
||||
type
|
||||
This attribute specifies the type of parameter. Currently supported types
|
||||
are *string*, *number*, *comma_delimited_list* or *json*.
|
||||
|
||||
description
|
||||
This *optional* attribute allows for giving a human readable description of
|
||||
the parameter.
|
||||
|
||||
default
|
||||
This *optional* attribute allows for defining a default value for the
|
||||
parameters which will be used in case the parameter is not specified by the
|
||||
user during deployment.
|
||||
|
||||
hidden
|
||||
This *optional* attribute allows for specifying whether the parameters
|
||||
should be hidden when showing information about a stack created from the
|
||||
template at runtime (e.g. for hiding passwords that were specified as
|
||||
parameters). If not specified, the default value 'false' will be used.
|
||||
|
||||
constraints
|
||||
This *optional* block allows for specifying additional constraints on the
|
||||
parameter, such as minimum or maximum values for numeric parameters.
|
||||
|
||||
The following example shows a minimalistic definition of two parameters. Note
|
||||
that the description is actually optional, but is good practice to provide a
|
||||
useful description for each parameter.
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
user_name:
|
||||
type: string
|
||||
description: User name to be configured for the application
|
||||
port_number:
|
||||
type: number
|
||||
description: Port number to be configured for the web server
|
||||
|
||||
|
||||
.. _hot_spec_parameters_constraints:
|
||||
|
||||
Parameter Constraints
|
||||
---------------------
|
||||
|
||||
The *constraints* block of a parameter definition allows for defining additional
|
||||
validation constraints that apply to the value of the parameter. At
|
||||
instantiation time of the template, user provided parameter values are validated
|
||||
against those constraints to make sure the provided values match expectations of
|
||||
the template author.
|
||||
Constraints are defined in the form of a bulleted list according to the
|
||||
following syntax:
|
||||
|
||||
::
|
||||
|
||||
constraints:
|
||||
- <constraint type>: <constraint definition>
|
||||
description: <constraint description>
|
||||
|
||||
constraint type
|
||||
The constraint type specifies the kind of constraint defined in the current
|
||||
bulleted list item. The set of currently supported constraints is given
|
||||
below.
|
||||
|
||||
constraint definition
|
||||
This value defines the actual constraint, depending on the constraint type.
|
||||
The concrete syntax for each constraint type is given below.
|
||||
|
||||
description
|
||||
This *optional* attribute allows for specifying a concrete description of
|
||||
the current constraint. This text will be presented to the user, for
|
||||
example, when the provided input value for a parameter violates the
|
||||
constraint. If omitted, a default validation message will be presented to
|
||||
the user.
|
||||
|
||||
The following example show the definition of a string parameter with two
|
||||
constraints. Note that while the descriptions for each constraint are optional,
|
||||
it is good practice to provide concrete descriptions so useful messages can be
|
||||
presented to the user at deployment time.
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
user_name:
|
||||
type: string
|
||||
description: User name to be configured for the application
|
||||
constraints:
|
||||
- length: { min: 6, max: 8 }
|
||||
description: User name must be between 6 and 8 characters
|
||||
- allowed_pattern: "[A-Z]+[a-zA-Z0-9]*"
|
||||
description: User name must start with an uppercase character
|
||||
|
||||
The following sections list the supported types of parameter constraints, along
|
||||
with the concrete syntax for each type.
|
||||
|
||||
length
|
||||
~~~~~~
|
||||
The *length* constraint applies to parameters of type *string* and allows for
|
||||
defining a lower and upper limit for the length of the string value. The syntax
|
||||
for the length constraint is:
|
||||
|
||||
::
|
||||
|
||||
length: { min: <lower limit>, max: <upper limit> }
|
||||
|
||||
It is possible to define a length constraint with only a lower limit or an
|
||||
upper limit. However, at least one of *min* or *max* must be specified.
|
||||
|
||||
range
|
||||
~~~~~
|
||||
The *range* constraint applies to parameters of type *number* and allows for
|
||||
defining a lower and upper limit for the numeric value of the parameter. The
|
||||
syntax of the range constraint is:
|
||||
|
||||
::
|
||||
|
||||
range: { min: <lower limit>, max: <upper limit> }
|
||||
|
||||
It is possible to define a range constraint with only a lower limit or an
|
||||
upper limit. However, at least one of *min* or *max* must be specified.
|
||||
The minimum or maximum boundaries are included in the range. For example, the
|
||||
following range constraint would allow for all numeric values between 0 and 10.
|
||||
|
||||
::
|
||||
|
||||
range: { min: 0, max: 10 }
|
||||
|
||||
|
||||
allowed_values
|
||||
~~~~~~~~~~~~~~
|
||||
The *allowed_values* constraint applies to parameters of type string or number
|
||||
and allows for specifying a set of possible values for a parameter. At
|
||||
deployment time, the user provided value for the respective parameter must
|
||||
match one of the elements of the specified list. The syntax of the
|
||||
allowed_values constraint is:
|
||||
|
||||
::
|
||||
|
||||
allowed_values: [ <value>, <value>, ... ]
|
||||
|
||||
Alternatively, the YAML bulleted list notation can be used:
|
||||
|
||||
::
|
||||
|
||||
allowed_values:
|
||||
- <value>
|
||||
- <value>
|
||||
- ...
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
instance_type:
|
||||
type: string
|
||||
description: Instance type for compute instances
|
||||
constraints:
|
||||
allowed_values:
|
||||
- m1.small
|
||||
- m1.medium
|
||||
- m1.large
|
||||
|
||||
allowed_pattern
|
||||
~~~~~~~~~~~~~~~
|
||||
The *allowed_pattern* constraint applies to parameters of type string and allows
|
||||
for specifying a regular expression against which a user provided parameter
|
||||
value must evaluate at deployment
|
||||
The syntax of the allowed_pattern constraint is:
|
||||
|
||||
::
|
||||
|
||||
allowed_pattern: <regular expression>
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
user_name:
|
||||
type: string
|
||||
description: User name to be configured for the application
|
||||
constraints:
|
||||
- allowed_pattern: "[A-Z]+[a-zA-Z0-9]*"
|
||||
description: User name must start with an uppercase character
|
||||
|
||||
|
||||
.. _hot_spec_resources:
|
||||
|
||||
-----------------
|
||||
Resources Section
|
||||
-----------------
|
||||
|
||||
In the *resources* section, the templates for actual resources that will make up
|
||||
a stack deployed from the HOT template (e.g. compute instances, networks,
|
||||
storage volumes) are defined.
|
||||
Each resource is defined as a separate block in the resources section according
|
||||
to the syntax below.
|
||||
|
||||
::
|
||||
|
||||
resources:
|
||||
<resource ID>:
|
||||
type: <resource type>
|
||||
properties:
|
||||
<property name>: <property value>
|
||||
# more resource specific metadata
|
||||
|
||||
resource ID
|
||||
A resource block is headed by the resource ID, which must be unique within
|
||||
the resource section of a template.
|
||||
type
|
||||
This attribute specifies the type of resource, such as OS::Nova::Compute.
|
||||
properties
|
||||
This section contains a list of resource specific properties. The property
|
||||
value can be provided in place, or can be provided via a function
|
||||
(see :ref:`_hot_spec_intrinsic_functions`).
|
||||
|
||||
Depending on the type of resource, the resource block might include more
|
||||
resource specific metadata. Basically all resource types that can be used in
|
||||
CFN templates can also be used in HOT templates, adapted to the YAML structure
|
||||
as outlined above.
|
||||
Below is an example of a simple compute resource definition with some fixed
|
||||
property values.
|
||||
|
||||
::
|
||||
|
||||
resources:
|
||||
my_instance:
|
||||
type: OS::Nova::Compute
|
||||
properties:
|
||||
instance_type: m1.small
|
||||
image_id: F18-x86_64-cfntools
|
||||
|
||||
|
||||
.. _hot_spec_outputs:
|
||||
|
||||
---------------
|
||||
Outputs Section
|
||||
---------------
|
||||
|
||||
In the *outputs* section, any output parameters that should be available to the
|
||||
user can be defined. Typically, this would be, for example, parameters such as
|
||||
IP addresses of deployed instances, or URLs of web applications deployed as part
|
||||
of a stack.
|
||||
|
||||
Output parameters are defined according to the following syntax:
|
||||
|
||||
::
|
||||
|
||||
outputs:
|
||||
<parameter name>: <parameter value>
|
||||
|
||||
parameter name
|
||||
The name of the output parameter is defined as a key in the outputs section.
|
||||
parameter value
|
||||
This element specifies the value of the output parameter. Typically, this
|
||||
will be resolved by means of a function, e.g. by getting an attribute value
|
||||
of one of the stack's resources (see also
|
||||
:ref:`_hot_spec_intrinsic_functions`).
|
||||
|
||||
The example below shows, how the public IP address of a compute resource can be
|
||||
defined as an output parameter.
|
||||
|
||||
::
|
||||
|
||||
outputs:
|
||||
instance_ip: { get_attr: [my_instance, PublicIp] }
|
||||
|
||||
|
||||
.. _hot_spec_intrinsic_functions:
|
||||
|
||||
-------------------
|
||||
Intrinsic Functions
|
||||
-------------------
|
||||
HOT provides a set of intrinsic functions that can be used inside HOT templates
|
||||
to perform specific tasks, such as getting the value of a resource attribute at
|
||||
runtime. A definition of all intrinsic functions available in HOT is given
|
||||
below.
|
||||
|
||||
get_param
|
||||
---------
|
||||
The *get_param* function allows for referencing an input parameter of a template
|
||||
from anywhere within a template. At runtime, it will be resolved to the value
|
||||
provided for this input parameter. The syntax of the get_param function is as
|
||||
follows:
|
||||
|
||||
::
|
||||
|
||||
get_param: <parameter name>
|
||||
|
||||
The *parameter name* of the input parameter to be resolved is given as single
|
||||
parameter to this function. A sample use of this function in context of a
|
||||
resource definition is shown below.
|
||||
|
||||
::
|
||||
|
||||
parameters:
|
||||
instance_type:
|
||||
type: string
|
||||
description: Instance type to be used.
|
||||
|
||||
resources:
|
||||
my_instance:
|
||||
type: OS::Nova::Compute
|
||||
properties:
|
||||
instance_type: { get_param: instance_type}
|
||||
|
||||
|
||||
get_attr
|
||||
--------
|
||||
The *get_attr* function allows for referencing an attribute of a resource. At
|
||||
runtime, it will be resolved to the value of an attribute of a resource instance
|
||||
created from the respective resource definition of the template.
|
||||
The syntax of the get_attr function is as follows:
|
||||
|
||||
::
|
||||
|
||||
get_attr: [ <resource ID>: <attribute name> ]
|
||||
|
||||
resource ID
|
||||
This parameter specifies the resource the attribute of which shall be
|
||||
resolved. This resource must be defined within the *resources* section of
|
||||
the template (see also :ref:`_hot_spec_resources`).
|
||||
attribute name
|
||||
This parameter specifies the attribute to be resolved.
|
||||
|
||||
An example of using the get_attr function is shown below:
|
||||
|
||||
::
|
||||
|
||||
resources:
|
||||
my_instance:
|
||||
type: OS::Nova::Compute
|
||||
# ...
|
||||
|
||||
outputs:
|
||||
instance_ip: { get_attr: [my_instance, PublicIp] }
|
@ -20,4 +20,6 @@ Template Guide
|
||||
functions
|
||||
openstack
|
||||
cfn
|
||||
rackspace
|
||||
rackspace
|
||||
hot_guide
|
||||
hot_spec
|
||||
|
Loading…
Reference in New Issue
Block a user