Software-config hook for ansible
Added ansible to the software-config README Created a new folder elements/heat-config-ansible that will be pre-installed by diskimage-builder on any images wishing to use the ansible hook. Created an example ansible heat template with an example ansible script as a starting point. Updated README.rst to reflect how heat-config-ansible interacts with the HOT template. Change-Id: I861e96186e2f5d5b65ea5100edf1b82e753c425c
This commit is contained in:
parent
4e549c3ae6
commit
16a6afc80b
@ -33,6 +33,7 @@ with the following:
|
||||
os-collect-config \
|
||||
os-refresh-config \
|
||||
os-apply-config \
|
||||
heat-config-ansible \
|
||||
heat-config-cfn-init \
|
||||
heat-config-puppet \
|
||||
heat-config-script \
|
||||
|
@ -0,0 +1,4 @@
|
||||
A hook which invokes ``ansible-playbook -i "localhost,"`` on the provided
|
||||
configuration. Config inputs are written to a 'variables.json' file and
|
||||
then passed to ansible via the '--extra-vars @json_file' parameter.
|
||||
Config output values are read from written-out files.
|
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install-packages ansible
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-ansible.py /var/lib/heat-config/hooks/ansible
|
95
hot/software-config/elements/heat-config-ansible/install.d/hook-ansible.py
Executable file
95
hot/software-config/elements/heat-config-ansible/install.d/hook-ansible.py
Executable file
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
WORKING_DIR = os.environ.get('HEAT_ANSIBLE_WORKING',
|
||||
'/var/lib/heat-config/heat-config-ansible')
|
||||
OUTPUTS_DIR = os.environ.get('HEAT_ANSIBLE_OUTPUTS',
|
||||
'/var/run/heat-config/heat-config-ansible')
|
||||
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
log = logging.getLogger('heat-config')
|
||||
handler = logging.StreamHandler(sys.stderr)
|
||||
handler.setFormatter(
|
||||
logging.Formatter(
|
||||
'[%(asctime)s] (%(name)s) [%(levelname)s] %(message)s'))
|
||||
log.addHandler(handler)
|
||||
log.setLevel('DEBUG')
|
||||
|
||||
prepare_dir(OUTPUTS_DIR)
|
||||
prepare_dir(WORKING_DIR)
|
||||
os.chdir(WORKING_DIR)
|
||||
|
||||
c = json.load(sys.stdin)
|
||||
|
||||
variables = {}
|
||||
for input in c['inputs']:
|
||||
variables[input['name']] = input.get('value','')
|
||||
|
||||
fn = os.path.join(WORKING_DIR, '%s_playbook.yaml' % c['id'])
|
||||
vars_filename = os.path.join(WORKING_DIR, '%s_variables.json' % c['id'])
|
||||
heat_outputs_path = os.path.join(OUTPUTS_DIR, c['id'])
|
||||
variables['heat_outputs_path'] = heat_outputs_path
|
||||
|
||||
config_text = c.get('config','')
|
||||
if not config_text:
|
||||
log.warn("No 'config' input found, nothing to do.")
|
||||
return
|
||||
#Write 'variables' to file
|
||||
with os.fdopen(os.open(vars_filename, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as var_file:
|
||||
json.dump(variables, var_file)
|
||||
#Write the executable, 'config', to file
|
||||
with os.fdopen(os.open(fn, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f:
|
||||
f.write(c.get('config',''))
|
||||
|
||||
cmd = ['ansible-playbook','-i','localhost,', fn, '--extra-vars','@%s' % vars_filename]
|
||||
log.debug('Running %s' % (' '.join(cmd),))
|
||||
try:
|
||||
subproc = subprocess.Popen([cmd], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, env=env)
|
||||
except OSError:
|
||||
log.warn("ansible not installed yet")
|
||||
return
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
log.info('Return code %s' % subproc.returncode)
|
||||
if stdout:
|
||||
log.info(stdout)
|
||||
if stderr:
|
||||
log.info(stderr)
|
||||
|
||||
#TODO: Test if ansible returns any non-zero return codes in success.
|
||||
if subproc.returncode:
|
||||
log.error("Error running %s. [%s]\n" % (fn, subproc.returncode))
|
||||
else:
|
||||
log.info('Completed %s' % fn)
|
||||
|
||||
response = {}
|
||||
|
||||
for output in c.get('outputs') or []:
|
||||
output_name = output['name']
|
||||
try:
|
||||
with open('%s.%s' % (heat_outputs_path, output_name)) as out:
|
||||
response[output_name] = out.read()
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
response.update({
|
||||
'deploy_stdout': stdout,
|
||||
'deploy_stderr': stderr,
|
||||
'deploy_status_code': subproc.returncode,
|
||||
})
|
||||
|
||||
json.dump(response, sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Hello Ansible - quick start
|
||||
connection: local
|
||||
hosts: localhost
|
||||
|
||||
tasks:
|
||||
- name: Hello touch_file
|
||||
shell: echo {{ foo }} >> /tmp/{{ bar }}
|
||||
|
||||
- name: Hello echo
|
||||
shell: echo "The file /tmp/{{ bar }} contains {{ foo }}" >> {{ heat_outputs_path }}.result
|
@ -0,0 +1,89 @@
|
||||
heat_template_version: 2013-05-23
|
||||
parameters:
|
||||
key_name:
|
||||
type: string
|
||||
default: test_key
|
||||
flavor:
|
||||
type: string
|
||||
default: m1.heat
|
||||
image:
|
||||
type: string
|
||||
default: fedora-software-config
|
||||
|
||||
resources:
|
||||
the_sg:
|
||||
type: OS::Neutron::SecurityGroup
|
||||
properties:
|
||||
name: the_sg
|
||||
description: Ping and SSH
|
||||
rules:
|
||||
- protocol: icmp
|
||||
- protocol: tcp
|
||||
port_range_min: 22
|
||||
port_range_max: 22
|
||||
|
||||
config:
|
||||
type: OS::Heat::SoftwareConfig
|
||||
properties:
|
||||
group: ansible
|
||||
inputs:
|
||||
- name: foo
|
||||
- name: bar
|
||||
outputs:
|
||||
- name: result
|
||||
config:
|
||||
get_file: config-scripts/example-ansible-template.ansible
|
||||
|
||||
deployment:
|
||||
type: OS::Heat::SoftwareDeployment
|
||||
properties:
|
||||
config:
|
||||
get_resource: config
|
||||
server:
|
||||
get_resource: server
|
||||
input_values:
|
||||
foo: fooooo
|
||||
bar: baaaaa
|
||||
|
||||
other_deployment:
|
||||
type: OS::Heat::SoftwareDeployment
|
||||
properties:
|
||||
config:
|
||||
get_resource: config
|
||||
server:
|
||||
get_resource: server
|
||||
input_values:
|
||||
foo: fu
|
||||
bar: barmy
|
||||
actions:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
- SUSPEND
|
||||
- RESUME
|
||||
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
image: {get_param: image}
|
||||
flavor: {get_param: flavor}
|
||||
key_name: {get_param: key_name}
|
||||
security_groups:
|
||||
- {get_resource: the_sg}
|
||||
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]
|
||||
other_result:
|
||||
value:
|
||||
get_attr: [other_deployment, result]
|
Loading…
Reference in New Issue
Block a user