Heat/Blueprints/hot-software-config
Contents
HOT Software Config
--stevebaker (talk) 21:10, 15 October 2013 (UTC)
NOTE: This specification is still under discussion and has not been endorsed by the heat project.
Background
The blueprint software-configuration-provider and its specification [1] are the most complete attempt so far to specify the HOT solution to Heat software config.
The blueprints hot-software-config and hot-software-config-deps appear to be closely related to software-configuration-provider
This specification is attempting to solve the same problems as [2] but takes an alternative approach in some areas. It is hoped that a consensus is reached among heat-core developers so that implementation can begin.
The blueprint native-tools-bootstrap-config and specification [3] is related to this specification, and will evolve together as changes are made.
Also see Angus's fantastic (giggle) approach at this [4]
Components vs Resources: Representing software config
A heat resource represents the configuration and life-cycle of a cloud resource which is managed via its API. A small number of heat resources do not map to a cloud resource, and instead represent internal heat state. This has often been the cause of issues and serves as a warning to using the resource abstraction for purposes it was not designed for. Other orchestration/configuration management tools have chosen single abstractions to represent both orchestration and configuration management. Depending on the abstraction chosen, generally one or other of these areas end up with a poor representation in these tools.
Component definition
Software configuration for Heat involves defining units of work (components) that need to be executed on compute resources whenever that resource is created or updated.
Each component needs to be able to specify the following:
- The type of the configuration component
- Configuration data which represents the unit of work the component will perform
A HOT template will have a new top-level section called components. Just like resources, components will contain named blocks where each block represents a single component that can be referenced elsewhere by its name. Each component will also have the following attributes:
-
typespecifies which component implementation to use, which indicates the which configuration management tool syntax will be used in theconfigsection. -
configdata which is passed to the configuration management tool to perform the component's desired configuration. There is no processing of HOT intrinsic functions inconfigblocks; they are intended to be self-contained units of configuration. Ideally it should be possible to invoke the content ofconfigsections directly with the configuration management tool without any modification or involvement from Heat. Depending on the format required by the configuration management tool, theconfigattribute could either contain a string containing a script, or a YAML structure. -
config-fileas an alternative toconfigspecifies a URL or relative file path to load configuration from. Paths that resolve to local files will need to be resolved by the heat client.
An example of a components section:
components:
install_mysql:
type: Heat::SoftwareConfig
config:
packages:
yum:
mysql: []
mysql-server: []
services:
systemd:
mysqld: {enabled: 'true', ensureRunning: 'true'}
install_wordpress:
type: Heat::SoftwareConfig
config:
packages:
yum:
httpd: []
wordpress: []
services:
systemd:
httpd: {enabled: 'true', ensureRunning: 'true'}
foo_file:
type: Heat::SoftwareConfig
config:
files:
/tmp/foo/bar:
content: 'foo_bar_contents'
Component invocation
Components can only be invoked on compute resources. The properties for AWS::EC2::Instance must remain compatible with cfn, however OS::Nova::Server has no such limitation. OS::Nova::Server will gain a components property which specifies a list of components to apply to the server in the desired order. Each entry in the components list will contain the following properties:
-
namethe name of the component to invoke, as specified in thecomponentssection -
paramsvalues from stack resources, parameters, attributes or static values get mapped to configuration management variables in each component. How these params get treated will depend on the component type, and the configuration management tool used by that type.
An example of a OS::Nova::Server with a components property:
resources:
the_server:
type: OS::Nova::Server
properties:
components:
- name: install_things
- name: write_foo_bar
params:
foo_bar_contents:
get_param: the_file_contents
- name: repo_epel_5_testing
- name: some_user_data
Why not relationships hosted_on, depends_on, connects_to?
A previous proposal for HOT components specified that each component definition can specify a relationships attribute which allows the following relations to be defined:
-
hosted_onthe defining component is hosted on the referenced component or resource -
depends_onthe defining component has a general dependency on the referenced component or resource -
connects_tothe defining component needs to connect to the referenced component or resource. In contrast to depends_on, a connects_to relation generally involves execution of some code to establish the connection
This proposal deliberately does not have a relationships attribute at all. Each relationship type is not need for the following reasons:
-
hosted_onis represented in thecomponentsproperty of the OS::Nova::Server.hosted_onreverses the convention that Heat already has in establishing a relationship between two entities. If the component/resource relationship is defined by the resource then a layering can be established whereby the component layer never makes reference to the stack/resource layer. -
depends_onis represented by the order of the components specified in thecomponentsproperty of the OS::Nova::Server. Practically speaking, one component does not "depend on" another at all. Instead one component might have some precondition which could be satisfied by another specific component, or by a different component which performs that precondition in a different way, or that precondition might already be satisfied by the server image. Modelling the satisfaction of these preconditions is a core purpose of many configuration management tools. Doing this in HOT components would be reinventing something which is more completely implemented by the very tools that some components will be using. Therefore this proposal takes the position that component dependencies should not be modeled at all, and template authors should ensure themselves that preconditions of a component are satisfied either through specifying component order, or by building custom images. -
connects_tothe proposal of this relationship type does not yet have enough detail to evaluate it, but if it is necessary there should be a way of modelling it in another way.
Composability
The stated intent of HOT components is to separate application configuration from stack architecture, and to allow application configuration components to be reused in different templates.
Composability is maximized by using the config-file attribute so that configuration scripts exist as their own re-usable files. Consider the following pseudo example:
components:
install_db:
type: Heat::Puppet
config-file: install_db.pp
configure_db_for_app:
type: Heat::Puppet
config-file: configure_db_for_app.pp
configure_app:
type: Heat::Puppet
config-file: configure_app.pp
resources:
db_and_app:
type: OS::Nova::Server
properties:
components:
- name: install_db
- name: configure_db_for_app
- name: configure_app
params:
db_server: localhost
A template which specifies a simple 2-tier architecture could specify an identical components section and specify the following for the resources:
resources:
db_server:
type: OS::Nova::Server
properties:
components:
- name: install_db
- name: configure_db_for_app
app_server:
type: OS::Nova::Server
properties:
components:
- name: configure_app
params:
db_server:
get_attr: [db_server, first_address]
Another template could specify load balanced HA of the app_server while still using the same configure_app.pp component configuration.
Concurrency and dependencies
Consider the following resources:
resources:
db_server:
type: OS::Nova::Server
app_server:
type: OS::Nova::Server
properties:
components:
- name: do_first_thing
- name: configure_app
params:
db_server:
get_attr: [db_server, first_address]
- name: do_last_thing
Heat's current behavior would be to not start creating the resource app_server until db_server creation is completed. This dependency is determined by the call to get_attr: [db_server, first_address] in the configure_app component.
However there is potential for increased concurrency in this scenario. app_server could be created at the same time as db_server, and the do_first_thing component can perform its configuration. Further configuration progress can then block until db_server is created, then configure_app and do_last_thing can perform their configuration.
Consider the following alternative to app_server:
app_server:
type: OS::Nova::Server
properties:
component_execution: async
components:
- name: do_first_thing
- name: configure_app
params:
db_server:
get_attr: [db_server, first_address]
- name: do_last_thing
Specifying component_execution: async would do the following:
- Prevent resource dependencies from being established for any get_attr or get_resource calls inside the
componentsproperty (in this case,app_serverwill no longer depend ondb_server) - Prevent metadata for
configure_appanddo_last_thingfrom being built at all until all values are able to be resolved - Rely on os-collect-config polling to trigger
configure_appanddo_last_thingwhendb_servercreation is complete.
Wait conditions
Currently in Heat, wait conditions are the accepted way to communicate data or events from servers back to the orchestration engine. Currently writing templates with wait conditions can be cumbersome since it requires:
- a wait condition resource
- a wait handle resource
- server configuration to invoke cfn-signal (or curl) with the wait handle URL
- a
get_attrcall on the wait condition to establish a resource dependency on the wait condition result.
A completely different mechanism may be implemented in the future, but in the meantime this blueprint should enable a more succinct representation of waitconditions to simplify their use.
The actual approach will be specified by blueprint hot-software-config-deps so this will not be explored in detail here, but one possible solution is presented just to confirm that components have the potential of allowing this simplification:
components:
install_db:
type: Heat::Puppet
config-file: install_db.pp
configure_db_for_app:
type: Heat::Puppet
config-file: configure_db_for_app.pp
return_db_url:
type: Heat::WaitCondition
config: |
#!/bin/sh
# shell script which builds and returns a db URL
configure_app:
type: Heat::Puppet
config-file: configure_app.pp
resources:
db_server:
type: OS::Nova::Server
properties:
components:
- name: install_db
- name: configure_db_for_app
- name: return_db_url
params:
wait_condition_resource: db_server_url
app_server:
type: OS::Nova::Server
properties:
components:
- name: configure_app
params:
db_server:
get_attr [db_server_url, first_data]
Here, the Heat::WaitCondition component implements whatever is required to call cfn-signal with some arbitrary data, so that the only job of the config script is to build the data to be signaled.
Specifying wait_condition_resource: db_server_url will implicitly create the wait handle resource and the wait condition resource that can be referenced by other resources.