os-refresh-config script to invoke config hooks

This orc script takes a list of heat config metadata under
the 'deployments' key and invokes a hook for each config item.

Hooks are stored in /var/lib/heat-config/hooks and the config group
name is used to specify which hook script to invoke.

A hook receives the config JSON on stdin and writes a JSON dict containing
outputs data to stdout. The orc script takes the outputs dict and signals
that back to heat using either a cfn signal post or a heatclient
resource-signal library call.

The following changes in this series contain hook implementations
and example templates.

Change-Id: Ia02005c28d550a195771dfacbba5fd71a39db709
This commit is contained in:
Steve Baker 2014-04-03 13:49:28 +13:00 committed by Thomas Herve
parent 40e6c0874d
commit 14a1de95f0
6 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,3 @@
This is an os-refresh-config script which iterates over deployments configuration
data and invokes the appropriate hook for each deployment item. Any outputs returned
by the hook will be signalled back to heat using the configured signalling method.

View File

@ -0,0 +1,2 @@
os-apply-config
os-refresh-config

View File

@ -0,0 +1,8 @@
#!/bin/bash
set -eux
install-packages python-pip
pip install python-heatclient
SCRIPTDIR=$(dirname $0)
install -D -g root -o root -m 0600 ${SCRIPTDIR}/heat-config /var/run/heat-config/heat-config

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,107 @@
#!/usr/bin/env python
import json
import logging
import os
import requests
import subprocess
import sys
HOOKS_DIR = os.environ.get('HEAT_CONFIG_HOOKS',
'/var/lib/heat-config/hooks')
CONF_FILE = os.environ.get('HEAT_SHELL_CONFIG',
'/var/run/heat-config/heat-config')
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')
if not os.path.exists(CONF_FILE):
log.error('No config file %s' % CONF_FILE)
return 1
try:
configs = json.load(open(CONF_FILE))
except ValueError:
pass
else:
for c in configs:
try:
invoke_hook(c, log)
except Exception as e:
log.exception(e)
def invoke_hook(c, log):
# sanitise the group to get an alphanumeric hook file name
hook = "".join(
x for x in c['group'] if x == '-' or x == '_' or x.isalnum())
hook_path = os.path.join(HOOKS_DIR, hook)
signal_data = None
if not os.path.exists(hook_path):
log.warn('Skipping group %s with no hook script %s' % (
c['group'], hook_path))
else:
log.debug('Running %s' % hook_path)
subproc = subprocess.Popen([hook_path],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = subproc.communicate(input=json.dumps(c))
log.info(stdout)
log.debug(stderr)
if subproc.returncode:
log.error("Error running %s. [%s]\n" % (
hook_path, subproc.returncode))
else:
log.info('Completed %s' % hook_path)
try:
if stdout:
signal_data = json.dumps(json.loads(stdout))
except ValueError:
signal_data = json.dumps({
'deploy_stdout': stdout,
'deploy_stderr': stderr,
'deploy_status_code': subproc.returncode,
})
iv = dict((i['name'], i['value']) for i in c['inputs'])
if signal_data:
if 'deploy_signal_id' in iv:
sigurl = iv.get('deploy_signal_id')
log.debug('Signalling to %s with %s' % (sigurl, signal_data))
r = requests.post(sigurl, data=signal_data,
headers={'content-type': None})
log.debug('Response %s ' % r)
if 'deploy_auth_url' in iv:
from heatclient import client as heatclient
from keystoneclient.v3 import client as ksclient
ks = ksclient.Client(
auth_url=iv['deploy_auth_url'],
user_id=iv['deploy_user_id'],
password=iv['deploy_password'],
project_id=iv['deploy_project_id'])
endpoint = ks.service_catalog.url_for(
service_type='orchestration', endpoint_type='publicURL')
log.debug('Signalling to %s' % endpoint)
heat = heatclient.Client(
'1', endpoint, token=ks.auth_token)
r = heat.resources.signal(
iv.get('deploy_stack_id'),
iv.get('deploy_resource_name'),
data=signal_data)
log.debug('Response %s ' % r)
if __name__ == '__main__':
sys.exit(main(sys.argv))