258 lines
6.1 KiB
Python
258 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
'''
|
|
Module for handling Heat stacks.
|
|
|
|
:depends: - python-heatclient>=0.2.3 Python module
|
|
:configuration: This module is not usable until the following are specified
|
|
either in a pillar or in the minion's config file::
|
|
|
|
keystone.user: admin
|
|
keystone.password: verybadpass
|
|
keystone.tenant: admin
|
|
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
|
keystone.insecure: False #(optional)
|
|
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
|
|
|
|
If configuration for multiple openstack accounts is required, they can be
|
|
set up as different configuration profiles:
|
|
For example::
|
|
|
|
openstack1:
|
|
keystone.user: admin
|
|
keystone.password: verybadpass
|
|
keystone.tenant: admin
|
|
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
|
keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
|
|
|
|
openstack2:
|
|
keystone.user: admin
|
|
keystone.password: verybadpass
|
|
keystone.tenant: admin
|
|
keystone.tenant_id: f80919baedab48ec8931f200c65a50df
|
|
keystone.auth_url: 'http://127.0.0.2:5000/v2.0/'
|
|
|
|
With this configuration in place, any of the heat functions can make
|
|
use of a configuration profile by declaring it explicitly.
|
|
For example::
|
|
|
|
salt '*' heat.stack_list profile=openstack1
|
|
|
|
'''
|
|
|
|
from __future__ import absolute_import
|
|
import logging
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
# Import third party libs
|
|
HAS_HEAT = False
|
|
try:
|
|
from heatclient.v1 import client
|
|
HAS_HEAT = True
|
|
except Exception, e:
|
|
LOG.trace("heatclient or keystone is not installed %s" % e)
|
|
|
|
import json
|
|
import glob
|
|
from os.path import basename
|
|
from yaml import load, dump
|
|
|
|
HEAT_ROOT = "/srv/heat/env"
|
|
|
|
TEMPLATE_PATH = "template"
|
|
ENV_PATH ="env"
|
|
|
|
HOT = ".hot"
|
|
ENV = ".env"
|
|
|
|
HOT_MASK = "*%s" % HOT
|
|
ENV_MASK = "*%s" % ENV
|
|
|
|
|
|
def _autheticate(func_name):
|
|
'''
|
|
Authenticate requests with the salt keystone module and format return data
|
|
'''
|
|
@wraps(func_name)
|
|
def decorator_method(*args, **kwargs):
|
|
'''
|
|
Authenticate request and format return data
|
|
'''
|
|
connection_args = {'profile': kwargs.get('profile', None)}
|
|
nkwargs = {}
|
|
for kwarg in kwargs:
|
|
if 'connection_' in kwarg:
|
|
connection_args.update({kwarg: kwargs[kwarg]})
|
|
elif '__' not in kwarg:
|
|
nkwargs.update({kwarg: kwargs[kwarg]})
|
|
kstone = __salt__['keystone.auth'](**connection_args)
|
|
token = kstone.auth_token
|
|
endpoint = kstone.service_catalog.url_for(
|
|
service_type='orchestration',
|
|
endpoint_type='publicURL')
|
|
heat_interface = client.Client(
|
|
endpoint_url=endpoint, token=token)
|
|
return_data = func_name(heat_interface, *args, **nkwargs)
|
|
if isinstance(return_data, list):
|
|
# format list as a dict for rendering
|
|
return {data.get('name', None) or data['id']: data
|
|
for data in return_data}
|
|
return return_data
|
|
return decorator_method
|
|
|
|
|
|
def _filename(path):
|
|
"""
|
|
helper
|
|
return filename without extension
|
|
"""
|
|
return basename(path).split(".")[0]
|
|
|
|
|
|
def _get_templates(choices=True):
|
|
"""
|
|
if choices is False return array of full path
|
|
"""
|
|
|
|
path = "/".join([HEAT_ROOT, TEMPLATE_PATH])
|
|
|
|
templates = []
|
|
|
|
for path in glob.glob("/".join([path, HOT_MASK])):
|
|
name = filename(path)
|
|
templates.append((name, name.replace("_", " ").capitalize()))
|
|
|
|
return sorted(templates)
|
|
|
|
|
|
def _get_environments(template_name=None):
|
|
"""return environments choices
|
|
"""
|
|
path = "/".join([HEAT_ROOT, ENV_PATH])
|
|
|
|
environments = []
|
|
|
|
if template_name:
|
|
join = [path, template_name, ENV_MASK]
|
|
else:
|
|
join = [path, ENV_MASK]
|
|
|
|
for path in glob.glob("/".join(join)):
|
|
name = filename(path)
|
|
environments.append((name, name.replace("_", " ").capitalize()))
|
|
|
|
return sorted(environments)
|
|
|
|
|
|
def _get_template_data(name):
|
|
"""
|
|
load and return template data
|
|
"""
|
|
|
|
path = "/".join([
|
|
HEAT_ROOT,
|
|
TEMPLATE_PATH,
|
|
"".join([name, HOT])
|
|
])
|
|
|
|
try:
|
|
f = open(path, 'r')
|
|
data = load(f)
|
|
except Exception, e:
|
|
raise e
|
|
|
|
return data
|
|
|
|
|
|
def _get_environment_data(template_name, name):
|
|
"""
|
|
load and return parameters data
|
|
"""
|
|
|
|
path = "/".join([
|
|
HEAT_ROOT,
|
|
ENV_PATH,
|
|
template_name,
|
|
"".join([name, ENV])
|
|
])
|
|
|
|
try:
|
|
f = open(path, 'r')
|
|
data = load(f)
|
|
except Exception, e:
|
|
raise e
|
|
|
|
return data
|
|
|
|
|
|
def __virtual__():
|
|
'''
|
|
Only load this module if Heat
|
|
is installed on this minion.
|
|
'''
|
|
if HAS_HEAT:
|
|
return 'heat'
|
|
return False
|
|
|
|
__opts__ = {}
|
|
|
|
|
|
def stack_list(tenant=None, **kwargs):
|
|
|
|
heat = heatclient()
|
|
|
|
ret = {}
|
|
ret["result"] = heat.stacks.list()
|
|
|
|
return ret
|
|
|
|
|
|
def stack_create(template, environment=None, name=None, parameters=None, timeout_mins=5,
|
|
enable_rollback=True, **kwargs):
|
|
'''
|
|
Return a specific endpoint (gitlab endpoint-get)
|
|
|
|
:params template: template name
|
|
:params name: if not provided template will be used
|
|
|
|
CLI Example:
|
|
|
|
.. code-block:: bash
|
|
|
|
salt '*' heat.stack_create template_name
|
|
'''
|
|
|
|
heat = heatclient()
|
|
|
|
# get template
|
|
|
|
template_data = get_template_data(template)
|
|
|
|
# Validate the template and get back the params.
|
|
kwargs = {}
|
|
kwargs['template'] = str(json.dumps(template_data, cls=CustomEncoder))
|
|
|
|
try:
|
|
validated = heat.stacks.validate(**kwargs)
|
|
except Exception as e:
|
|
LOG.error("Template not valid %s" % e)
|
|
|
|
fields = {
|
|
'stack_name': name,
|
|
'template': json.dumps(template_data, cls=CustomEncoder),
|
|
'environment': parameters,
|
|
'parameters': parameters,
|
|
'timeout_mins': timeout_mins,
|
|
'disable_rollback': enable_rollback,
|
|
}
|
|
#LOG.debug(dir(heat))
|
|
|
|
heat.stacks.create(**fields)
|
|
|
|
return {'status': result}
|
|
|
|
|
|
def stack_delete(template, name=None, parameters=None, **kwargs):
|
|
|
|
return {'Error': 'Could not delete stack.'}
|
|
|