Remove all deprecated hooks and tests. Also since all test and hooks are removed, we can remove the declare of python language in classifier. Since we didn't actually provide any document, we should remove docs too. Hooks are maintained as Agents under heat-agents repo now. Hooks in heat-templates are deprecated for a while. Hence, remove hooks in heat-templates. Depends-On: https://review.openstack.org/#/c/584774/ Change-Id: Ia886f71eaf99d75db0f9a6a7dfbe8664995c26e7changes/77/584777/14
parent
2b4eb5d9e3
commit
53800d1057
@ -1,18 +0,0 @@
|
||||
.. heat-templates documentation master file, created by
|
||||
sphinx-quickstart on Thu Jul 20 09:19:39 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Heat Templates!
|
||||
==========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
@ -1,51 +0,0 @@
|
||||
============================
|
||||
Software configuration hooks
|
||||
============================
|
||||
|
||||
.. warning::
|
||||
All hooks (heat agents) in heat-templates repository are deprecated,
|
||||
please use hooks in `heat-agents https://git.openstack.org/cgit/openstack/heat-agents` instead.
|
||||
Here is document entry for heat-agents: `https://docs.openstack.org/heat-agents/latest/`
|
||||
|
||||
This directory contains `diskimage-builder <https://github.com/openstack/diskimage-builder>`_
|
||||
elements to build an image which contains the software configuration hook
|
||||
required to use your preferred configuration method.
|
||||
|
||||
These elements depend on some elements found in the
|
||||
`tripleo-image-elements <https://github.com/openstack/tripleo-image-elements>`_
|
||||
repository. These elements will build an image which uses
|
||||
`os-collect-config <https://github.com/openstack/os-collect-config>`_,
|
||||
`os-refresh-config <https://github.com/openstack/os-refresh-config>`_, and
|
||||
`os-apply-config <https://github.com/openstack/os-apply-config>`_ together to
|
||||
invoke a hook with the supplied configuration data, and return any outputs back
|
||||
to heat.
|
||||
|
||||
When building an image only the elements for the preferred configuration methods are required. The heat-config element is automatically included as a dependency.
|
||||
|
||||
An example fedora based image containing all hooks can be built and uploaded to glance
|
||||
with the following:
|
||||
|
||||
::
|
||||
|
||||
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
|
||||
git clone https://git.openstack.org/openstack/dib-utils.git
|
||||
export PATH="${PWD}/dib-utils/bin:$PATH"
|
||||
export ELEMENTS_PATH=tripleo-image-elements/elements:heat-templates/hot/software-config/elements
|
||||
diskimage-builder/bin/disk-image-create vm \
|
||||
fedora selinux-permissive \
|
||||
os-collect-config \
|
||||
os-refresh-config \
|
||||
os-apply-config \
|
||||
heat-config \
|
||||
heat-config-ansible \
|
||||
heat-config-cfn-init \
|
||||
heat-config-docker-compose \
|
||||
heat-config-kubelet \
|
||||
heat-config-puppet \
|
||||
heat-config-salt \
|
||||
heat-config-script \
|
||||
-o fedora-software-config.qcow2
|
||||
openstack image create --disk-format qcow2 --container-format bare fedora-software-config < \
|
||||
fedora-software-config.qcow2
|
@ -1,4 +0,0 @@
|
||||
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.
|
@ -1 +0,0 @@
|
||||
heat-config
|
@ -1,7 +0,0 @@
|
||||
#!/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
|
@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
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')
|
||||
ANSIBLE_CMD = os.environ.get('HEAT_ANSIBLE_CMD', 'ansible-playbook')
|
||||
ANSIBLE_INVENTORY = os.environ.get('HEAT_ANSIBLE_INVENTORY', 'localhost,')
|
||||
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
|
||||
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', '')
|
||||
|
||||
tags = c['options'].get('tags')
|
||||
modulepath = c['options'].get('modulepath')
|
||||
|
||||
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', '').encode('utf-8'))
|
||||
|
||||
cmd = [
|
||||
ANSIBLE_CMD,
|
||||
'-i',
|
||||
ANSIBLE_INVENTORY,
|
||||
fn,
|
||||
'--extra-vars',
|
||||
'@%s' % vars_filename
|
||||
]
|
||||
if tags:
|
||||
cmd.insert(3, '--tags')
|
||||
cmd.insert(4, tags)
|
||||
if modulepath:
|
||||
cmd.insert(3, '--module-path')
|
||||
cmd.insert(4, modulepath)
|
||||
|
||||
log.debug('Running %s' % (' '.join(cmd),))
|
||||
try:
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
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(stevebaker): 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))
|
@ -1,14 +0,0 @@
|
||||
A hook which invokes os-apply-config.
|
||||
|
||||
The intent is for this element (hook script) to be used in place of the one in
|
||||
tripleo-image-elements which relies on an external signal handling
|
||||
shell script at the end of the os-refresh-config run (99-refresh-completed).
|
||||
This version will run os-apply-config and return a signal immediately. Because
|
||||
it uses the heat-hook mechanisms it also supports a broader set of signal
|
||||
handling capabilities... which 99-refresh-completed doesn't fully support.
|
||||
|
||||
It is worth noting that this hook runs os-apply-config against all the
|
||||
accumulated metadata, not just data supplied to an individual hook.
|
||||
|
||||
To use this hook set group: to 'apply-config' instead of 'os-apply-config'
|
||||
in your Heat software configuration resources.
|
@ -1 +0,0 @@
|
||||
heat-config
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-apply-config.py /var/lib/heat-config/hooks/apply-config
|
@ -1,60 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
APPLY_CONFIG_CMD = os.environ.get('HEAT_APPLY_CONFIG_CMD', 'os-apply-config')
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
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')
|
||||
|
||||
env = os.environ.copy()
|
||||
|
||||
log.debug('Running %s' % APPLY_CONFIG_CMD)
|
||||
subproc = subprocess.Popen([APPLY_CONFIG_CMD], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, env=env)
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
log.info(stdout)
|
||||
log.debug(stderr)
|
||||
|
||||
if subproc.returncode:
|
||||
log.error("Error running apply-config: [%s]\n" % subproc.returncode)
|
||||
else:
|
||||
log.info('Completed apply-config.')
|
||||
|
||||
response = {
|
||||
'deploy_stdout': stdout,
|
||||
'deploy_stderr': stderr,
|
||||
'deploy_status_code': subproc.returncode,
|
||||
}
|
||||
|
||||
json.dump(response, sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,3 +0,0 @@
|
||||
A hook which consumes configuration in the format of AWS::CloudFormation::Init
|
||||
metadata. It is provided to enable migrating from CloudFormation metadata
|
||||
configuration to configuration using config and deployment resources.
|
@ -1 +0,0 @@
|
||||
heat-config
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-cfn-init.py /var/lib/heat-config/hooks/cfn-init
|
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
|
||||
# Ideally this path would be /var/lib/heat-cfntools/cfn-init-data
|
||||
# but this is where all boot metadata is stored
|
||||
LAST_METADATA_DIR = os.environ.get('HEAT_CFN_INIT_LAST_METADATA_DIR',
|
||||
'/var/cache/heat-cfntools')
|
||||
|
||||
|
||||
CFN_INIT_CMD = os.environ.get('HEAT_CFN_INIT_CMD',
|
||||
'cfn-init')
|
||||
|
||||
|
||||
def main(argv=sys.argv, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
|
||||
log = logging.getLogger('heat-config')
|
||||
handler = logging.StreamHandler(stderr)
|
||||
handler.setFormatter(
|
||||
logging.Formatter(
|
||||
'[%(asctime)s] (%(name)s) [%(levelname)s] %(message)s'))
|
||||
log.addHandler(handler)
|
||||
log.setLevel('DEBUG')
|
||||
|
||||
c = json.load(stdin)
|
||||
|
||||
config = c.get('config', {})
|
||||
if not isinstance(config, dict):
|
||||
config = json.loads(config)
|
||||
meta = {'AWS::CloudFormation::Init': config}
|
||||
|
||||
if not os.path.isdir(LAST_METADATA_DIR):
|
||||
os.makedirs(LAST_METADATA_DIR, 0o700)
|
||||
|
||||
fn = os.path.join(LAST_METADATA_DIR, 'last_metadata')
|
||||
with os.fdopen(os.open(fn, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o700),
|
||||
'w') as f:
|
||||
json.dump(meta, f)
|
||||
|
||||
log.debug('Running %s' % CFN_INIT_CMD)
|
||||
subproc = subprocess.Popen([CFN_INIT_CMD], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
cstdout, cstderr = subproc.communicate()
|
||||
|
||||
if cstdout:
|
||||
log.info(cstdout)
|
||||
if cstderr:
|
||||
log.info(cstderr)
|
||||
|
||||
if subproc.returncode:
|
||||
log.error("Error running %s. [%s]\n" % (
|
||||
CFN_INIT_CMD, subproc.returncode))
|
||||
else:
|
||||
log.info('Completed %s' % CFN_INIT_CMD)
|
||||
|
||||
response = {
|
||||
'deploy_stdout': cstdout,
|
||||
'deploy_stderr': cstderr,
|
||||
'deploy_status_code': subproc.returncode,
|
||||
}
|
||||
|
||||
json.dump(response, stdout)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,36 +0,0 @@
|
||||
A hook which invokes ``chef-client`` in local mode (chef zero) on the
|
||||
provided configuration.
|
||||
|
||||
Inputs:
|
||||
-------
|
||||
Inputs are attribute overrides. In order to format them correctly for
|
||||
consumption, you need to explicitly declare each top-level section as an
|
||||
input of type ``Json`` in your config resource.
|
||||
|
||||
Additionally, there is a special input named ``environment`` of type
|
||||
``String`` that you can use to specify which environment to use when
|
||||
applying the config. You do not have to explicitly declare this input in
|
||||
the config resource.
|
||||
|
||||
Outputs:
|
||||
--------
|
||||
If you need to capture specific outputs from your chef run, you should
|
||||
specify the output name(s) as normal in your config. Then, your recipes
|
||||
should write files to the directory specified by the ``heat_outputs_path``
|
||||
environment variable. The file name should match the name of the output
|
||||
you are trying to capture.
|
||||
|
||||
Options:
|
||||
-------------
|
||||
|
||||
kitchen : optional
|
||||
A URL for a Git repository containing the desired recipes, roles,
|
||||
environments and other configuration.
|
||||
|
||||
This will be cloned into ``kitchen_path`` for use by chef.
|
||||
|
||||
kitchen_path : default ``/var/lib/heat-config/heat-config-chef/kitchen``
|
||||
Instance-local path for the recipes, roles, environments, etc.
|
||||
|
||||
If ``kitchen`` is not specified, this directory must be populated via
|
||||
user-data, another software config, or other "manual" method.
|
@ -1 +0,0 @@
|
||||
heat-config
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install-packages chef git
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-chef.py /var/lib/heat-config/hooks/chef
|
@ -1,165 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import six
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
DEPLOY_KEYS = ("deploy_server_id",
|
||||
"deploy_action",
|
||||
"deploy_stack_id",
|
||||
"deploy_resource_name",
|
||||
"deploy_signal_transport",
|
||||
"deploy_signal_id",
|
||||
"deploy_signal_verb")
|
||||
WORKING_DIR = os.environ.get('HEAT_CHEF_WORKING',
|
||||
'/var/lib/heat-config/heat-config-chef')
|
||||
OUTPUTS_DIR = os.environ.get('HEAT_CHEF_OUTPUTS',
|
||||
'/var/run/heat-config/heat-config-chef')
|
||||
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
|
||||
def run_subproc(fn, **kwargs):
|
||||
env = os.environ.copy()
|
||||
for k, v in kwargs.items():
|
||||
env[six.text_type(k)] = v
|
||||
try:
|
||||
subproc = subprocess.Popen(fn, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=env)
|
||||
stdout, stderr = subproc.communicate()
|
||||
except OSError as exc:
|
||||
ret = -1
|
||||
stderr = six.text_type(exc)
|
||||
stdout = ""
|
||||
else:
|
||||
ret = subproc.returncode
|
||||
if not ret:
|
||||
ret = 0
|
||||
return ret, stdout, stderr
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
|
||||
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)
|
||||
|
||||
client_config = ("log_level :debug\n"
|
||||
"log_location STDOUT\n"
|
||||
"local_mode true\n"
|
||||
"chef_zero.enabled true")
|
||||
|
||||
# configure/set up the kitchen
|
||||
kitchen = c['options'].get('kitchen')
|
||||
kitchen_path = c['options'].get('kitchen_path', os.path.join(WORKING_DIR,
|
||||
"kitchen"))
|
||||
cookbook_path = os.path.join(kitchen_path, "cookbooks")
|
||||
role_path = os.path.join(kitchen_path, "roles")
|
||||
environment_path = os.path.join(kitchen_path, "environments")
|
||||
client_config += "\ncookbook_path '%s'" % cookbook_path
|
||||
client_config += "\nrole_path '%s'" % role_path
|
||||
client_config += "\nenvironment_path '%s'" % environment_path
|
||||
if kitchen:
|
||||
log.debug("Cloning kitchen from %s", kitchen)
|
||||
# remove the existing kitchen on update so we get a fresh clone
|
||||
dep_action = next((input['value'] for input in c['inputs']
|
||||
if input['name'] == "deploy_action"), None)
|
||||
if dep_action == "UPDATE":
|
||||
shutil.rmtree(kitchen_path, ignore_errors=True)
|
||||
cmd = ["git", "clone", kitchen, kitchen_path]
|
||||
ret, out, err = run_subproc(cmd)
|
||||
if ret != 0:
|
||||
log.error("Error cloning kitchen from %s into %s: %s", kitchen,
|
||||
kitchen_path, err)
|
||||
json.dump({'deploy_status_code': ret,
|
||||
'deploy_stdout': out,
|
||||
'deploy_stderr': err},
|
||||
sys.stdout)
|
||||
return 0
|
||||
|
||||
# write the json attributes
|
||||
ret, out, err = run_subproc(['hostname', '-f'])
|
||||
if ret == 0:
|
||||
fqdn = out.strip()
|
||||
else:
|
||||
err = "Could not determine hostname with hostname -f"
|
||||
json.dump({'deploy_status_code': ret,
|
||||
'deploy_stdout': "",
|
||||
'deploy_stderr': err}, sys.stdout)
|
||||
return 0
|
||||
node_config = {}
|
||||
for input in c['inputs']:
|
||||
if input['name'] == 'environment':
|
||||
client_config += "\nenvironment '%s'" % input['value']
|
||||
elif input['name'] not in DEPLOY_KEYS:
|
||||
node_config.update({input['name']: input['value']})
|
||||
node_config.update({"run_list": json.loads(c['config'])})
|
||||
node_path = os.path.join(WORKING_DIR, "node")
|
||||
prepare_dir(node_path)
|
||||
node_file = os.path.join(node_path, "%s.json" % fqdn)
|
||||
with os.fdopen(os.open(node_file, os.O_CREAT | os.O_WRONLY, 0o600),
|
||||
'w') as f:
|
||||
f.write(json.dumps(node_config, indent=4))
|
||||
client_config += "\nnode_path '%s'" % node_path
|
||||
|
||||
# write out the completed client config
|
||||
config_path = os.path.join(WORKING_DIR, "client.rb")
|
||||
with os.fdopen(os.open(config_path, os.O_CREAT | os.O_WRONLY, 0o600),
|
||||
'w') as f:
|
||||
f.write(client_config)
|
||||
|
||||
# run chef
|
||||
heat_outputs_path = os.path.join(OUTPUTS_DIR, c['id'])
|
||||
cmd = ['chef-client', '-z', '--config', config_path, "-j", node_file]
|
||||
ret, out, err = run_subproc(cmd, heat_outputs_path=heat_outputs_path)
|
||||
resp = {'deploy_status_code': ret,
|
||||
'deploy_stdout': out,
|
||||
'deploy_stderr': err}
|
||||
log.debug("Chef output: %s", out)
|
||||
if err:
|
||||
log.error("Chef return code %s:\n%s", ret, err)
|
||||
for output in c.get('outputs', []):
|
||||
output_name = output['name']
|
||||
try:
|
||||
with open('%s.%s' % (heat_outputs_path, output_name)) as out:
|
||||
resp[output_name] = out.read()
|
||||
except IOError:
|
||||
pass
|
||||
json.dump(resp, sys.stdout)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,9 +0,0 @@
|
||||
A hook which uses the `docker` command to deploy containers.
|
||||
|
||||
The hook currently supports specifying containers in the `docker-compose v1
|
||||
format <https://docs.docker.com/compose/compose-file/#/version-1>`_. The
|
||||
intention is for this hook to also support the kubernetes pod format.
|
||||
|
||||
A dedicated os-refresh-config script will remove running containers if a
|
||||
deployment is removed or changed, then the docker-cmd hook will run any
|
||||
containers in new or updated deployments.
|
@ -1,2 +0,0 @@
|
||||
os-apply-config
|
||||
os-refresh-config
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-docker-cmd.py /var/lib/heat-config/hooks/docker-cmd
|
@ -1,143 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import six
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
import yaml
|
||||
|
||||
|
||||
DOCKER_CMD = os.environ.get('HEAT_DOCKER_CMD', 'docker')
|
||||
|
||||
|
||||
log = None
|
||||
|
||||
|
||||
def build_response(deploy_stdout, deploy_stderr, deploy_status_code):
|
||||
return {
|
||||
'deploy_stdout': deploy_stdout,
|
||||
'deploy_stderr': deploy_stderr,
|
||||
'deploy_status_code': deploy_status_code,
|
||||
}
|
||||
|
||||
|
||||
def docker_arg_map(key, value):
|
||||
value = str(value).encode('ascii', 'ignore')
|
||||
return {
|
||||
'container_step_config': None,
|
||||
'environment': "--env=%s" % value,
|
||||
'image': value,
|
||||
'net': "--net=%s" % value,
|
||||
'pid': "--pid=%s" % value,
|
||||
'privileged': "--privileged=%s" % 'true' if value else 'false',
|
||||
'restart': "--restart=%s" % value,
|
||||
'user': "--user=%s" % value,
|
||||
'volumes': "--volume=%s" % value,
|
||||
'volumes_from': "--volumes-from=%s" % value,
|
||||
}.get(key, None)
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
|
||||
global log
|
||||
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')
|
||||
|
||||
c = json.load(sys.stdin)
|
||||
|
||||
input_values = dict((i['name'], i['value']) for i in c.get('inputs', {}))
|
||||
|
||||
if input_values.get('deploy_action') == 'DELETE':
|
||||
json.dump(build_response(
|
||||
'', '', 0), sys.stdout)
|
||||
return
|
||||
|
||||
config = c.get('config', '')
|
||||
if not config:
|
||||
log.debug("No 'config' input found, nothing to do.")
|
||||
json.dump(build_response(
|
||||
'', '', 0), sys.stdout)
|
||||
return
|
||||
|
||||
stdout = []
|
||||
stderr = []
|
||||
deploy_status_code = 0
|
||||
|
||||
# convert config to dict
|
||||
if not isinstance(config, dict):
|
||||
config = yaml.safe_load(config)
|
||||
|
||||
for container in sorted(config):
|
||||
container_name = '%s__%s' % (c['name'], container)
|
||||
cmd = [
|
||||
DOCKER_CMD,
|
||||
'run',
|
||||
'--detach=true',
|
||||
'--name',
|
||||
container_name.encode('ascii', 'ignore'),
|
||||
]
|
||||
image_name = ''
|
||||
for key in sorted(config[container]):
|
||||
# These ones contain a list of values
|
||||
if key in ['environment', 'volumes', 'volumes_from']:
|
||||
for value in config[container][key]:
|
||||
# Somehow the lists get empty values sometimes
|
||||
if type(value) is six.text_type and not value.strip():
|
||||
continue
|
||||
cmd.append(docker_arg_map(key, value))
|
||||
elif key == 'image':
|
||||
image_name = config[container][key].encode('ascii', 'ignore')
|
||||
else:
|
||||
arg = docker_arg_map(key, config[container][key])
|
||||
if arg:
|
||||
cmd.append(arg)
|
||||
|
||||
# Image name must come last.
|
||||
cmd.append(image_name)
|
||||
|
||||
log.debug(' '.join(cmd))
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
cmd_stdout, cmd_stderr = subproc.communicate()
|
||||
log.debug(cmd_stdout)
|
||||
log.debug(cmd_stderr)
|
||||
if cmd_stdout:
|
||||
stdout.append(cmd_stdout)
|
||||
if cmd_stderr:
|
||||
stderr.append(cmd_stderr)
|
||||
|
||||
if subproc.returncode:
|
||||
log.error("Error running %s. [%s]\n" % (cmd, subproc.returncode))
|
||||
else:
|
||||
log.debug('Completed %s' % cmd)
|
||||
|
||||
if subproc.returncode != 0:
|
||||
deploy_status_code = subproc.returncode
|
||||
|
||||
json.dump(build_response(
|
||||
'\n'.join(stdout), '\n'.join(stderr), deploy_status_code), sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
CONF_FILE = os.environ.get('HEAT_SHELL_CONFIG',
|
||||
'/var/run/heat-config/heat-config')
|
||||
|
||||
WORKING_DIR = os.environ.get(
|
||||
'HEAT_DOCKER_CMD_WORKING',
|
||||
'/var/lib/heat-config/heat-config-docker-cmd')
|
||||
|
||||
DOCKER_CMD = os.environ.get('HEAT_DOCKER_CMD', 'docker')
|
||||
|
||||
|
||||
log = None
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
global log
|
||||
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.warning('No config file %s' % CONF_FILE)
|
||||
return 1
|
||||
|
||||
if not os.path.isdir(WORKING_DIR):
|
||||
os.makedirs(WORKING_DIR, 0o700)
|
||||
|
||||
try:
|
||||
configs = json.load(open(CONF_FILE))
|
||||
except ValueError as e:
|
||||
log.warning('Could not load config json: %s' % e)
|
||||
return 1
|
||||
|
||||
cmd_configs = list(build_configs(configs))
|
||||
try:
|
||||
delete_missing_projects(cmd_configs)
|
||||
for c in cmd_configs:
|
||||
delete_changed_project(c)
|
||||
write_project(c)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
|
||||
def build_configs(configs):
|
||||
for c in configs:
|
||||
if c['group'] != 'docker-cmd':
|
||||
continue
|
||||
if not isinstance(c['config'], dict):
|
||||
# convert config to dict
|
||||
c['config'] = yaml.safe_load(c['config'])
|
||||
yield c
|
||||
|
||||
|
||||
def current_projects():
|
||||
for proj_file in os.listdir(WORKING_DIR):
|
||||
if proj_file.endswith('.json'):
|
||||
proj = proj_file[:-5]
|
||||
yield proj
|
||||
|
||||
|
||||
def remove_project(proj):
|
||||
proj_file = os.path.join(WORKING_DIR, '%s.json' % proj)
|
||||
with open(proj_file, 'r') as f:
|
||||
proj_data = json.load(f)
|
||||
for name in extract_container_names(proj, proj_data):
|
||||
remove_container(name)
|
||||
os.remove(proj_file)
|
||||
|
||||
|
||||
def remove_container(name):
|
||||
cmd = [DOCKER_CMD, 'rm', '-f', name]
|
||||
log.debug(' '.join(cmd))
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = subproc.communicate()
|
||||
log.info(stdout)
|
||||
log.debug(stderr)
|
||||
|
||||
|
||||
def delete_missing_projects(configs):
|
||||
config_names = [c['name'] for c in configs]
|
||||
for proj in current_projects():
|
||||
if proj not in config_names:
|
||||
log.debug('%s no longer exists, deleting containers' % proj)
|
||||
remove_project(proj)
|
||||
|
||||
|
||||
def extract_container_names(proj, proj_data):
|
||||
# For now, assume a docker-compose v1 format where the
|
||||
# root keys are service names
|
||||
for name in sorted(proj_data):
|
||||
yield '%s__%s' % (proj, name)
|
||||
|
||||
|
||||
def delete_changed_project(c):
|
||||
proj = c['name']
|
||||
proj_file = os.path.join(WORKING_DIR, '%s.json' % proj)
|
||||
proj_data = c.get('config', {})
|
||||
if os.path.isfile(proj_file):
|
||||
with open(proj_file, 'r') as f:
|
||||
prev_proj_data = json.load(f)
|
||||
if proj_data != prev_proj_data:
|
||||
log.debug('%s has changed, deleting containers' % proj)
|
||||
remove_project(proj)
|
||||
|
||||
|
||||
def write_project(c):
|
||||
proj = c['name']
|
||||
proj_file = os.path.join(WORKING_DIR, '%s.json' % proj)
|
||||
proj_data = c.get('config', {})
|
||||
|
||||
with os.fdopen(os.open(
|
||||
proj_file, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600),
|
||||
'w') as f:
|
||||
json.dump(proj_data, f, indent=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,18 +0,0 @@
|
||||
A hook which uses `docker-compose` to deploy containers.
|
||||
|
||||
A special input 'env_files' can be used with SoftwareConfig and
|
||||
StructuredConfig for docker-compose `env_file` key(s).
|
||||
|
||||
if env_file keys specified in the `docker-compose.yml`, do not
|
||||
exist in input_values supplied, docker-compose will throw an
|
||||
error, as it can't find these files.
|
||||
|
||||
Also, `--parameter-file` option can be used to pass env files from client.
|
||||
|
||||
Example:
|
||||
|
||||
$ openstack stack create test_stack -t example-docker-compose-template.yaml \
|
||||
--parameter-file env_file_0=./common.env \
|
||||
--parameter-file env_file_1=./apps/web.env \
|
||||
--parameter-file env_file_2=./test.env \
|
||||
--parameter-file env_file_3=./busybox.env
|
@ -1,2 +0,0 @@
|
||||
os-apply-config
|
||||
os-refresh-config
|
@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
if [ -f /etc/debian_version ]; then
|
||||
install-packages docker.io
|
||||
update-rc.d docker.io defaults
|
||||
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
yum -y install docker-io
|
||||
systemctl enable docker.service
|
||||
fi
|
||||
|
||||
pip install -U dpath docker-compose==1.4.0
|
||||
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-docker-compose.py /var/lib/heat-config/hooks/docker-compose
|
@ -1,131 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import ast
|
||||
import dpath
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import six
|
||||
import subprocess
|
||||
import sys
|
||||
import warnings
|
||||
import yaml
|
||||
|
||||
|
||||
WORKING_DIR = os.environ.get('HEAT_DOCKER_COMPOSE_WORKING',
|
||||
'/var/lib/heat-config/heat-config-docker-compose')
|
||||
|
||||
DOCKER_COMPOSE_CMD = os.environ.get('HEAT_DOCKER_COMPOSE_CMD',
|
||||
'docker-compose')
|
||||
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
|
||||
def write_input_file(file_path, content):
|
||||
prepare_dir(os.path.dirname(file_path))
|
||||
with os.fdopen(os.open(
|
||||
file_path, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f:
|
||||
f.write(content.encode('utf-8'))
|
||||
|
||||
|
||||
def build_response(deploy_stdout, deploy_stderr, deploy_status_code):
|
||||
return {
|
||||
'deploy_stdout': deploy_stdout,
|
||||
'deploy_stderr': deploy_stderr,
|
||||
'deploy_status_code': deploy_status_code,
|
||||
}
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
warnings.warn('This hook is deprecated, please use hooks from heat-agents '
|
||||
'repository instead.', DeprecationWarning)
|
||||
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')
|
||||
|
||||
c = json.load(sys.stdin)
|
||||
|
||||
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
||||
|
||||
proj = os.path.join(WORKING_DIR, c.get('name'))
|
||||
prepare_dir(proj)
|
||||
|
||||
stdout, stderr = {}, {}
|
||||
|
||||
if input_values.get('deploy_action') == 'DELETE':
|
||||
json.dump(build_response(stdout, stderr, 0), sys.stdout)
|
||||
return
|
||||
|
||||
config = c.get('config', '')
|
||||
if not config:
|
||||
log.debug("No 'config' input found, nothing to do.")
|
||||
json.dump(build_response(stdout, stderr, 0), sys.stdout)
|
||||
return
|
||||
|
||||
# convert config to dict
|
||||
if not isinstance(config, dict):
|
||||
config = ast.literal_eval(json.dumps(yaml.safe_load(config)))
|
||||
|
||||
os.chdir(proj)
|
||||
|
||||
compose_env_files = []
|
||||
for value in dpath.util.values(config, '*/env_file'):
|
||||
if isinstance(value, list):
|
||||
compose_env_files.extend(value)
|
||||
elif isinstance(value, six.string_types):
|
||||
compose_env_files.extend([value])
|
||||
|
||||
input_env_files = {}
|
||||
if input_values.get('env_files'):
|
||||
input_env_files = dict(
|
||||
(i['file_name'], i['content'])
|
||||
for i in ast.literal_eval(input_values.get('env_files')))
|
||||
|
||||
for file in compose_env_files:
|
||||
if file in input_env_files.keys():
|
||||
write_input_file(file, input_env_files.get(file))
|
||||
|
||||
cmd = [
|
||||
DOCKER_COMPOSE_CMD,
|
||||
'up',
|
||||
'-d',
|
||||
'--no-build',
|
||||
]
|
||||
|
||||
log.debug('Running %s' % cmd)
|
||||
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
log.debug(stdout)
|
||||
log.debug(stderr)
|
||||
|
||||
if subproc.returncode:
|
||||
log.error("Error running %s. [%s]\n" % (cmd, subproc.returncode))
|
||||
else:
|
||||
log.debug('Completed %s' % cmd)
|
||||
|
||||
json.dump(build_response(stdout, stderr, subproc.returncode), sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,116 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
CONF_FILE = os.environ.get('HEAT_SHELL_CONFIG',
|
||||
'/var/run/heat-config/heat-config')
|
||||
|
||||
DOCKER_COMPOSE_DIR = os.environ.get(
|
||||
'HEAT_DOCKER_COMPOSE_WORKING',
|
||||
'/var/lib/heat-config/heat-config-docker-compose')
|
||||
|
||||
DOCKER_COMPOSE_CMD = os.environ.get('HEAT_DOCKER_COMPOSE_CMD',
|
||||
'docker-compose')
|
||||
|
||||
|
||||
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
|
||||
|
||||
if not os.path.isdir(DOCKER_COMPOSE_DIR):
|
||||
os.makedirs(DOCKER_COMPOSE_DIR, 0o700)
|
||||
|
||||
try:
|
||||
configs = json.load(open(CONF_FILE))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
cleanup_stale_projects(configs)
|
||||
for c in configs:
|
||||
write_compose_config(c)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
|
||||
def cleanup_stale_projects(configs):
|
||||
def deployments(configs):
|
||||
for c in configs:
|
||||
yield c['name']
|
||||
|
||||
def compose_projects(compose_dir):
|
||||
for proj in os.listdir(compose_dir):
|
||||
if os.path.isfile(
|
||||
os.path.join(DOCKER_COMPOSE_DIR,
|
||||
'%s/docker-compose.yml' % proj)):
|
||||
yield proj
|
||||
|
||||
def cleanup_containers(project):
|
||||
cmd = [
|
||||
DOCKER_COMPOSE_CMD,
|
||||
'kill'
|
||||
]
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
for proj in compose_projects(DOCKER_COMPOSE_DIR):
|
||||
if proj not in deployments(configs):
|
||||
proj_dir = os.path.join(DOCKER_COMPOSE_DIR, proj)
|
||||
os.chdir(proj_dir)
|
||||
cleanup_containers(proj)
|
||||
os.remove('%s/docker-compose.yml' % proj_dir)
|
||||
|
||||
|
||||
def write_compose_config(c):
|
||||
group = c.get('group')
|
||||
if group != 'docker-compose':
|
||||
return
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
compose_conf = c.get('config', '')
|
||||
if isinstance(compose_conf, dict):
|
||||
yaml_config = yaml.safe_dump(compose_conf, default_flow_style=False)
|
||||
else:
|
||||
yaml_config = compose_conf
|
||||
proj_dir = os.path.join(DOCKER_COMPOSE_DIR, c['name'])
|
||||
prepare_dir(proj_dir)
|
||||
fn = os.path.join(proj_dir, 'docker-compose.yml')
|
||||
with os.fdopen(os.open(fn, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600),
|
||||
'w') as f:
|
||||
f.write(yaml_config.encode('utf-8'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,25 +0,0 @@
|
||||
A hook which helps write hiera files to disk and creates
|
||||
the hiera.yaml to order them. This is typically used alongside
|
||||
of the puppet hook to generate Hiera in a more composable manner.
|
||||
|
||||
Example:
|
||||
|
||||
ComputeConfig:
|
||||
type: OS::Heat::StructuredConfig
|
||||
properties:
|
||||
group: hiera
|
||||
config:
|
||||
hierarchy:
|
||||
- compute
|
||||
datafiles:
|
||||
compute:
|
||||
debug: true
|
||||
db_connection: foo:/bar
|
||||
# customized hiera goes here...
|
||||
|
||||
This would write out:
|
||||
|
||||
1) An /etc/hiera.yaml config file with compute in the hierarchy.
|
||||
|
||||
2) An /etc/puppet/hieradata/compute.json file loaded with the
|
||||
custom hiera data.
|
@ -1 +0,0 @@
|
||||
heat-config
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
SCRIPTDIR=$(dirname $0)
|
||||
|
||||
install-packages hiera
|
||||
install -D -g root -o root -m 0755 ${SCRIPTDIR}/hook-hiera.py /var/lib/heat-config/hooks/hiera
|
||||
|
||||
ln -f -s /etc/puppet/hiera.yaml /etc/hiera.yaml
|
@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
|
||||
HIERA_DATADIR = os |