summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Yang (Gabriel) <Gabriel.yuyang@huawei.com>2017-01-04 06:36:33 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-01-04 06:36:33 +0000
commit5c859330549de91739b7c2ef31c040a208bb6840 (patch)
tree4c0d43ff90dfc40a9564cd6ca88dc1e3f6ec26ed
parente3f1c15416686a3e527529aa289d914811ebd66e (diff)
parent754ce1457182411e7e887b307fb66f280885ff7e (diff)
Merge "bottlenecks openstack Newton support"
-rw-r--r--[-rwxr-xr-x]utils/infra_setup/heat/__init__.py2
-rwxr-xr-xutils/infra_setup/heat/common.py467
-rw-r--r--[-rwxr-xr-x]utils/infra_setup/heat/manager.py140
-rwxr-xr-xutils/infra_setup/heat/template.py300
4 files changed, 329 insertions, 580 deletions
diff --git a/utils/infra_setup/heat/__init__.py b/utils/infra_setup/heat/__init__.py
index 83b8d15d..6dbd8d79 100755..100644
--- a/utils/infra_setup/heat/__init__.py
+++ b/utils/infra_setup/heat/__init__.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
diff --git a/utils/infra_setup/heat/common.py b/utils/infra_setup/heat/common.py
index c4a78249..28257ac7 100755
--- a/utils/infra_setup/heat/common.py
+++ b/utils/infra_setup/heat/common.py
@@ -8,385 +8,106 @@
##############################################################################
import os
-import re
-import ConfigParser
import logging
-import fileinput
-import consts.files as files
-import consts.parameters as parameters
+from keystoneauth1 import loading
+from keystoneauth1 import session
-# ------------------------------------------------------
-# List of common variables
-# ------------------------------------------------------
+log = logging.getLogger(__name__)
-LOG = None
-CONF_FILE = None
-DEPLOYMENT_UNIT = None
-ITERATIONS = None
+DEFAULT_HEAT_API_VERSION = '1'
+DEFAULT_NOVA_API_VERSION = '2'
+DEFAULT_GLANCE_API_VERSION = '2'
-BASE_DIR = None
-TEMPLATE_DIR = None
-TEMPLATE_NAME = None
-TEMPLATE_EXTENSION = None
-# ------------------------------------------------------
-# Initialization and Input 'heat_templates/'validation
-# ------------------------------------------------------
+def get_credentials():
+ """Returns a creds dictionary filled with parsed from env"""
+ creds = {}
+ keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
-def init(api=False):
- global BASE_DIR
- # BASE_DIR = os.getcwd()
- BASE_DIR = os.path.dirname(os.path.abspath(__file__))
- BASE_DIR = BASE_DIR.replace('/heat', '')
- BASE_DIR = InputValidation.validate_directory_exist_and_format(
- BASE_DIR, "Error 000001")
-
- conf_file_init(api)
- log_init()
- general_vars_init(api)
-
-
-def conf_file_init(api=False):
- global CONF_FILE
- if api:
- CONF_FILE = ConfigurationFile(files.get_sections_api(),
- '/tmp/bottlenecks.conf')
- else:
- CONF_FILE = ConfigurationFile(cf.get_sections(),
- '/tmp/bottlenecks.conf')
-
-
-def general_vars_init(api=False):
- global TEMPLATE_EXTENSION
- global TEMPLATE_NAME
- global TEMPLATE_DIR
- global ITERATIONS
-
- TEMPLATE_EXTENSION = '.yaml'
-
- # Check Section in Configuration File
- InputValidation.validate_configuration_file_section(
- files.GENERAL,
- "Section " + files.GENERAL +
- "is not present in configuration file")
-
- InputValidation.validate_configuration_file_section(
- files.OPENSTACK,
- "Section " + files.OPENSTACK +
- "is not present in configuration file")
-
- TEMPLATE_DIR = '/tmp/heat_templates/'
-
- if not api:
- # Validate template name
- InputValidation.validate_configuration_file_parameter(
- files.GENERAL,
- files.TEMPLATE_NAME,
- "Parameter " + files.TEMPLATE_NAME +
- "is not present in configuration file")
- TEMPLATE_NAME = CONF_FILE.get_variable(files.GENERAL,
- files.TEMPLATE_NAME)
- InputValidation.validate_file_exist(
- TEMPLATE_DIR + TEMPLATE_NAME,
- "The provided template file does not exist")
-
- # Validate and assign Iterations
- if files.ITERATIONS in CONF_FILE.get_variable_list(files.GENERAL):
- ITERATIONS = int(CONF_FILE.get_variable(files.GENERAL,
- files.ITERATIONS))
+ if keystone_api_version is None or keystone_api_version == '2':
+ keystone_v3 = False
+ tenant_env = 'OS_TENANT_NAME'
+ tenant = 'tenant_name'
else:
- ITERATIONS = 1
-
-
-def log_init():
- global LOG
- LOG = logging.getLogger()
- LOG.setLevel(level=logging.DEBUG)
- log_formatter = logging.Formatter("%(asctime)s --- %(message)s")
- file_handler = logging.FileHandler("{0}/{1}.log".format("./", "benchmark"))
- file_handler.setFormatter(log_formatter)
- file_handler.setLevel(logging.DEBUG)
- LOG.addHandler(file_handler)
-
-# ------------------------------------------------------
-# Configuration file access
-# ------------------------------------------------------
-
-
-class ConfigurationFile:
- """
- Used to extract data from the configuration file
- """
-
- def __init__(self, sections, config_file='conf.cfg'):
- """
- Reads configuration file sections
-
- :param sections: list of strings representing the sections to be
- loaded
- :param config_file: name of the configuration file (string)
- :return: None
- """
- InputValidation.validate_string(
- config_file, "The configuration file name must be a string")
- InputValidation.validate_file_exist(
- config_file, 'The provided configuration file does not exist')
- self.config = ConfigParser.ConfigParser()
- self.config.read(config_file)
- for section in sections:
- setattr(
- self, section, ConfigurationFile.
- _config_section_map(section, self.config))
-
- @staticmethod
- def _config_section_map(section, config_file):
- """
- Returns a dictionary with the configuration values for the specific
- section
-
- :param section: section to be loaded (string)
- :param config_file: name of the configuration file (string)
- :return: dict
- """
- dict1 = dict()
- options = config_file.options(section)
- for option in options:
- dict1[option] = config_file.get(section, option)
- return dict1
-
- def get_variable(self, section, variable_name):
- """
- Returns the value correspondent to a variable
-
- :param section: section to be loaded (string)
- :param variable_name: name of the variable (string)
- :return: string
- """
- message = "The variable name must be a string"
- InputValidation.validate_string(variable_name, message)
- if variable_name in self.get_variable_list(section):
- sect = getattr(self, section)
- return sect[variable_name]
- else:
- exc_msg = 'Parameter {} is not in the {} section of the ' \
- 'conf file'.format(variable_name, section)
- raise ValueError(exc_msg)
-
- def get_variable_list(self, section):
- """
- Returns the list of the available variables in a section
- :param section: section to be loaded (string)
- :return: list
- """
- try:
- return getattr(self, section)
- except:
- msg = 'Section {} not found in the configuration file'.\
- format(section)
- raise ValueError(msg)
-
-# ------------------------------------------------------
-# Manage files
-# ------------------------------------------------------
-
-
-def get_heat_template_params():
- """
- Returns the list of deployment parameters from the configuration file
- for the heat template
-
- :return: dict
- """
- heat_parameters_list = CONF_FILE.get_variable_list(
- files.DEPLOYMENT_PARAMETERS)
- testcase_parameters = dict()
- for param in heat_parameters_list:
- testcase_parameters[param] = CONF_FILE.get_variable(
- files.DEPLOYMENT_PARAMETERS, param)
- return testcase_parameters
-
-
-def get_testcase_params():
- """
- Returns the list of testcase parameters from the configuration file
-
- :return: dict
- """
- testcase_parameters = dict()
- parameters = CONF_FILE.get_variable_list(files.TESTCASE_PARAMETERS)
- for param in parameters:
- testcase_parameters[param] = CONF_FILE.get_variable(
- files.TESTCASE_PARAMETERS, param)
- return testcase_parameters
-
-
-def get_file_first_line(file_name):
- """
- Returns the first line of a file
-
- :param file_name: name of the file to be read (str)
- :return: str
- """
- message = "name of the file must be a string"
- InputValidation.validate_string(file_name, message)
- message = 'file {} does not exist'.format(file_name)
- InputValidation.validate_file_exist(file_name, message)
- res = open(file_name, 'r')
- return res.readline()
-
-
-def replace_in_file(file, text_to_search, text_to_replace):
- """
- Replaces a string within a file
-
- :param file: name of the file (str)
- :param text_to_search: text to be replaced
- :param text_to_replace: new text that will replace the previous
- :return: None
- """
- message = 'text to be replaced in the file must be a string'
- InputValidation.validate_string(text_to_search, message)
- message = 'text to replace in the file must be a string'
- InputValidation.validate_string(text_to_replace, message)
- message = "name of the file must be a string"
- InputValidation.validate_string(file, message)
- message = "The file does not exist"
- InputValidation.validate_file_exist(file, message)
- for line in fileinput.input(file, inplace=True):
- print(line.replace(text_to_search, text_to_replace).rstrip())
-
-# ------------------------------------------------------
-# Shell interaction
-# ------------------------------------------------------
-
-
-def run_command(command):
- LOG.info("Running command: {}".format(command))
- return os.system(command)
-
-# ------------------------------------------------------
-# Expose variables to other modules
-# ------------------------------------------------------
-
-
-def get_base_dir():
- return BASE_DIR
-
-
-def get_template_dir():
- return TEMPLATE_DIR
-
-# ------------------------------------------------------
-# Configuration Variables from Config File
-# ------------------------------------------------------
-
-
-def get_deployment_configuration_variables_from_conf_file():
- variables = dict()
- types = dict()
- all_variables = CONF_FILE.get_variable_list(files.EXPERIMENT_VNF)
- for var in all_variables:
- v = CONF_FILE.get_variable(files.EXPERIMENT_VNF, var)
- type = re.findall(r'@\w*', v)
- values = re.findall(r'\"(.+?)\"', v)
- variables[var] = values
- try:
- types[var] = type[0][1:]
- except IndexError:
- LOG.debug("No type has been specified for variable " + var)
- return variables
-
-# ------------------------------------------------------
-# benchmarks from Config File
-# ------------------------------------------------------
-
-
-def get_benchmarks_from_conf_file():
- requested_benchmarks = list()
- benchmarks = CONF_FILE.get_variable(
- files.GENERAL, files.BENCHMARKS).split(', ')
- for benchmark in benchmarks:
- requested_benchmarks.append(benchmark)
- return requested_benchmarks
-
-
-class InputValidation(object):
-
- @staticmethod
- def validate_string(param, message):
- if not isinstance(param, str):
- raise ValueError(message)
- return True
-
- @staticmethod
- def validate_integer(param, message):
- if not isinstance(param, int):
- raise ValueError(message)
- return True
-
- @staticmethod
- def validate_dictionary(param, message):
- if not isinstance(param, dict):
- raise ValueError(message)
- return True
-
- @staticmethod
- def validate_file_exist(file_name, message):
- if not os.path.isfile(file_name):
- raise ValueError(message + ' ' + file_name)
- return True
-
- @staticmethod
- def validate_directory_exist_and_format(directory, message):
- if not os.path.isdir(directory):
- raise ValueError(message)
- if not directory.endswith('/'):
- return directory + '/'
- return directory
-
- @staticmethod
- def validate_configuration_file_parameter(section, parameter, message):
- params = CONF_FILE.get_variable_list(section)
- if parameter not in params:
- raise ValueError(message)
- return True
-
- @staticmethod
- def validate_configuration_file_section(section, message):
- if section not in files.get_sections():
- raise ValueError(message)
- return True
-
- @staticmethod
- def validate_boolean(boolean, message):
- if isinstance(boolean, bool):
- return boolean
- if isinstance(boolean, str):
- if boolean == 'True':
- return True
- if boolean == 'False':
- return False
- raise ValueError(message)
-
- @staticmethod
- def validate_os_credentials(credentials):
- if not isinstance(credentials, dict):
- raise ValueError(
- 'The provided openstack_credentials '
- 'variable must be in dictionary format')
-
- credential_keys = ['user', 'password', 'ip_controller', 'heat_url',
- 'auth_uri', 'project']
- missing = [
- credential_key
- for credential_key in credential_keys
- if credential_key not in credentials.keys()
- ]
- if len(missing) == 0:
- return True
- msg = 'OpenStack Credentials Error! ' \
- 'The following parameters are missing: {}'.\
- format(", ".join(missing))
- raise ValueError(msg)
+ keystone_v3 = True
+ tenant_env = 'OS_PROJECT_NAME'
+ tenant = 'project_name'
+
+ # The most common way to pass these info to the script is to do it
+ # through environment variables.
+ creds.update({
+ "username": os.environ.get("OS_USERNAME"),
+ "password": os.environ.get("OS_PASSWORD"),
+ "auth_url": os.environ.get("OS_AUTH_URL"),
+ tenant: os.environ.get(tenant_env)
+ })
+
+ if keystone_v3:
+ if os.getenv('OS_USER_DOMAIN_NAME') is not None:
+ creds.update({
+ "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME')
+ })
+ if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None:
+ creds.update({
+ "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME')
+ })
+
+ cacert = os.environ.get("OS_CACERT")
+
+ if cacert is not None:
+ # each openstack client uses differnt kwargs for this
+ creds.update({"cacert": cacert,
+ "ca_cert": cacert,
+ "https_ca_cert": cacert,
+ "https_cacert": cacert,
+ "ca_file": cacert})
+ creds.update({"insecure": "True", "https_insecure": "True"})
+ if not os.path.isfile(cacert):
+ log.info("WARNING: The 'OS_CACERT' environment variable is set\
+ to %s but the file does not exist." % cacert)
+
+ return creds
+
+
+def get_session_auth():
+ loader = loading.get_plugin_loader('password')
+ creds = get_credentials()
+ auth = loader.load_from_options(**creds)
+ return auth
+
+
+def get_session():
+ auth = get_session_auth()
+ return session.Session(auth=auth)
+
+
+def get_endpoint(service_type, endpoint_type='publicURL'):
+ auth = get_session_auth()
+ return get_session().get_endpoint(auth=auth,
+ service_type=service_type,
+ endpoint_type=endpoint_type)
+
+
+def get_heat_api_version():
+ api_version = os.getenv('HEAT_API_VERSION')
+ if api_version is not None:
+ log.info("HEAT_API_VERSION is set in env as '%s'", api_version)
+ return api_version
+ return DEFAULT_HEAT_API_VERSION
+
+def get_nova_api_version():
+ api_version = os.getenv('OS_COMPUTE_API_VERSION')
+ if api_version is not None:
+ log.info("NOVA_API_VERSION is set in env as '%s'", api_version)
+ return api_version
+ return DEFAULT_NOVA_API_VERSION
+
+
+def get_glance_api_version():
+ api_version = os.getenv('OS_IMAGE_API_VERSION')
+ if api_version is not None:
+ log.info("GLANCE_API_VERSION is set in env as '%s'", api_version)
+ return api_version
+ return DEFAULT_GLANCE_API_VERSION \ No newline at end of file
diff --git a/utils/infra_setup/heat/manager.py b/utils/infra_setup/heat/manager.py
index f5a9b88d..3a270ac1 100755..100644
--- a/utils/infra_setup/heat/manager.py
+++ b/utils/infra_setup/heat/manager.py
@@ -7,82 +7,68 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-from heatclient import client as heat_client
-from keystoneclient.v2_0 import client as keystone_client
-from heatclient.common import template_utils
-
-import heat.common as common
-
-
-class HeatManager:
-
- def __init__(self, credentials):
- self.user = credentials['user']
- self.password = credentials['password']
- self.controller_ip = credentials['controller_ip']
- self.heat_url = credentials['heat_url']
- self.auth_uri = credentials['auth_uri']
- self.project_id = credentials['project']
- self.heat = None
-
- def heat_init(self):
- keystone = keystone_client.Client(username=self.user,
- password=self.password,
- tenant_name=self.project_id,
- auth_url=self.auth_uri)
- auth_token = keystone.auth_token
- self.heat_url = keystone.service_catalog.url_for(
- service_type='orchestration')
- self.heat = heat_client.Client('1', endpoint=self.heat_url,
- token=auth_token)
-
- def stacks_list(self, name=None):
- for stack in self.heat.stacks.list():
- if (name and stack.stack_name == name) or not name:
- common.LOG.info("stack name " + stack.stack_name)
- common.LOG.info("stack status " + stack.stack_status)
-
- def stack_generate(self, template_file, stack_name, parameters):
- self.heat_init()
- self.stacks_list()
- tpl_files, template = template_utils.get_template_contents(
- template_file)
-
- fields = {
- 'template': template,
- 'files': dict(list(tpl_files.items()))
- }
- self.heat.stacks.create(stack_name=stack_name, files=fields['files'],
- template=template, parameters=parameters)
- self.stacks_list(stack_name)
-
- def stack_is_deployed(self, stack_name):
- self.heat_init()
- if stack_name in self.heat.stacks.list():
- return True
- return False
+import time
+import common as op_utils
+from glanceclient.client import Client as GlanceClient
+from novaclient.client import Client as NovaClient
+
+
+def _get_glance_client():
+ sess = op_utils.get_session()
+ return GlanceClient(
+ op_utils.get_glance_api_version(),
+ session=sess)
+
+
+def _get_nova_client():
+ sess = op_utils.get_session()
+
+ return NovaClient(
+ op_utils.get_nova_api_version(),
+ session=sess)
+
+
+def stack_create_images(
+ imagefile=None,
+ image_name="bottlenecks_image"):
+ print "========== Create image in OS =========="
- def stack_check_status(self, stack_name):
- for stack in self.heat.stacks.list():
- if stack.stack_name == stack_name:
- return stack.stack_status
- return 'NOT_FOUND'
-
- def heat_validate_template(self, heat_template_file):
- self.heat_init()
- if not self.heat.stacks.validate(template=open(heat_template_file,
- 'r').read()):
- raise ValueError('The provided heat template "' +
- heat_template_file +
- '" is in the wrong format')
-
- def stack_delete(self, stack_name):
- self.heat_init()
- try:
- for stack in self.heat.stacks.list():
- if stack.stack_name == stack_name:
- self.heat.stacks.delete(stack.id)
- return True
- except:
- pass
+ if imagefile is None:
+ print "imagefile not set/found"
return False
+
+ glance = _get_glance_client()
+ image = glance.images.create(
+ name=image_name,
+ disk_format="qcow2",
+ container_format="bare")
+ with open(imagefile) as fimage:
+ glance.images.upload(image.id, fimage)
+
+ timeInQueue = 0
+ img_status = image.status
+ while img_status == "queued" and timeInQueue < 30:
+ print " image's status: " + img_status
+ time.sleep(1)
+ timeInQueue = timeInQueue + 1
+ img_status = glance.images.get(image.id).status
+
+ print "After %d seconds,image status is [%s]" % (timeInQueue, img_status)
+ return True if img_status == "active" else False
+
+
+def stack_create_keypairs(key_path, name="bottlenecks_keypair"):
+ print "========== Add keypairs in OS =========="
+ nova = _get_nova_client()
+ with open(key_path) as pkey:
+ nova.keypairs.create(name=name, public_key=pkey.read())
+
+
+def stack_create_flavors(
+ name="bottlenecks_flavor",
+ ram=4096,
+ vcpus=2,
+ disk=10):
+ print "========== Create flavors in OS =========="
+ nova = _get_nova_client()
+ nova.flavors.create(name=name, ram=ram, vcpus=vcpus, disk=disk)
diff --git a/utils/infra_setup/heat/template.py b/utils/infra_setup/heat/template.py
index f71e9166..28c20b72 100755
--- a/utils/infra_setup/heat/template.py
+++ b/utils/infra_setup/heat/template.py
@@ -7,151 +7,193 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-"""to create heat templates from the base template
-"""
-import os
-import json
-import shutil
-import common
-import consts.parameters as parameters
+"""Heat template and stack management"""
+import time
+import sys
+import logging
-class TreeNode:
+from heatclient import client as heatclient
+import common as op_utils
- def __init__(self):
- self.up = None
- self.down = []
- self.variable_name = ''
- self.variable_value = 0
- def add_child(self, node):
- node.up = self
- self.down.append(node)
+log = logging.getLogger(__name__)
- def get_parent(self):
- return self.up
- def get_children(self):
- if len(self.down) == 0:
- return []
- return self.down
+class HeatObject(object):
+ ''' base class for template and stack'''
+ def __init__(self):
+ self._heat_client = None
+ self.uuid = None
- def get_variable_name(self):
- return self.variable_name
+ def _get_heat_client(self):
+ '''returns a heat client instance'''
- def get_variable_value(self):
- return self.variable_value
+ if self._heat_client is None:
+ sess = op_utils.get_session()
+ heat_endpoint = op_utils.get_endpoint(service_type='orchestration')
+ self._heat_client = heatclient.Client(
+ op_utils.get_heat_api_version(),
+ endpoint=heat_endpoint, session=sess)
- def set_variable_name(self, name):
- self.variable_name = name
+ return self._heat_client
- def set_variable_value(self, value):
- self.variable_value = value
+ def status(self):
+ '''returns stack state as a string'''
+ heat = self._get_heat_client()
+ stack = heat.stacks.get(self.uuid)
+ return getattr(stack, 'stack_status')
- def get_path(self):
- ret_val = []
- if not self.up:
- ret_val.append(self)
- return ret_val
- for node in self.up.get_path():
- ret_val.append(node)
- ret_val.append(self)
- return ret_val
- def __str__(self):
- return str(self.variable_name) + " --> " + str(self.variable_value)
+class HeatStack(HeatObject):
+ ''' Represents a Heat stack (deployed template) '''
+ stacks = []
- def __repr__(self):
- return str(self.variable_name) + " = " + str(self.variable_value)
+ def __init__(self, name):
+ super(HeatStack, self).__init__()
+ self.uuid = None
+ self.name = name
+ self.outputs = None
+ HeatStack.stacks.append(self)
@staticmethod
- def _get_leaves(node, leaves):
- children = node.get_children()
- if len(children) == 0:
- leaves.append(node)
+ def stacks_exist():
+ '''check if any stack has been deployed'''
+ return len(HeatStack.stacks) > 0
+
+ def _delete(self):
+ '''deletes a stack from the target cloud using heat'''
+ if self.uuid is None:
return
- for child in children:
- TreeNode._get_leaves(child, leaves)
+
+ log.info("Deleting stack '%s', uuid:%s", self.name, self.uuid)
+ heat = self._get_heat_client()
+ template = heat.stacks.get(self.uuid)
+ start_time = time.time()
+ template.delete()
+ status = self.status()
+
+ while status != u'DELETE_COMPLETE':
+ log.debug("stack state %s", status)
+ if status == u'DELETE_FAILED':
+ raise RuntimeError(
+ heat.stacks.get(self.uuid).stack_status_reason)
+
+ time.sleep(2)
+ status = self.status()
+
+ end_time = time.time()
+ log.info("Deleted stack '%s' in %d secs", self.name,
+ end_time - start_time)
+ self.uuid = None
+
+ def delete(self, block=True, retries=3):
+ '''deletes a stack in the target cloud using heat (with retry)
+ Sometimes delete fail with "InternalServerError" and the next attempt
+ succeeds. So it is worthwhile to test a couple of times.
+ '''
+ if self.uuid is None:
+ return
+
+ if not block:
+ try:
+ self._delete()
+ except RuntimeError as err:
+ log.warn(err.args)
+ HeatStack.stacks.remove(self)
+ return
+
+ i = 0
+ while i < retries:
+ try:
+ self._delete()
+ break
+ except RuntimeError as err:
+ log.warn(err.args)
+ time.sleep(2)
+ i += 1
+
+ if self.uuid is not None:
+ sys.exit("delete stack failed!!!")
+ else:
+ HeatStack.stacks.remove(self)
@staticmethod
- def get_leaves(node):
- leaves = list()
- TreeNode._get_leaves(node, leaves)
- return leaves
-
-template_name = parameters.TEST_TEMPLATE_NAME
-
-
-def generates_templates(base_heat_template, deployment_configuration):
- # parameters loaded from file
- template_dir = common.get_template_dir()
- template_extension = parameters.TEMPLATE_EXTENSION
- template_base_name = base_heat_template
-
- variables = deployment_configuration
-
- # Delete the templates generated in previous running
- common.LOG.info("Removing the heat templates already generated")
- command = "rm {}{}_*".format(template_dir, template_name)
- os.system(command)
-
- # Creation of the tree with all the new configurations
- common.LOG.info("Creation of a tree with all new configurations")
- tree = TreeNode()
- for variable in variables:
- leaves = TreeNode.get_leaves(tree)
- common.LOG.debug("LEAVES: " + str(leaves))
- common.LOG.debug("VALUES: " + str(variables[variable]))
-
- for value in variables[variable]:
- for leaf in leaves:
- new_node = TreeNode()
- new_node.set_variable_name(variable)
- new_node.set_variable_value(value)
- leaf.add_child(new_node)
-
- common.LOG.debug("CONFIGURATION TREE: " + str(tree))
-
- common.LOG.info("Heat Template and metadata file creation")
- leaves = TreeNode.get_leaves(tree)
- counter = 1
- for leaf in leaves:
- heat_template_vars = leaf.get_path()
- if os.path.isabs(template_base_name):
- base_template = template_base_name
+ def delete_all():
+ for stack in HeatStack.stacks[:]:
+ stack.delete()
+
+ def update(self):
+ '''update a stack'''
+ pass
+
+
+class HeatTemplate(HeatObject):
+ '''Describes a Heat template and a method to deploy template to a stack'''
+
+ def __init__(self, name, template_file=None, heat_parameters=None):
+ super(HeatTemplate, self).__init__()
+ self.name = name
+ self.state = "NOT_CREATED"
+ self.keystone_client = None
+ self.heat_client = None
+ self.heat_parameters = {}
+
+ # heat_parameters is passed to heat in stack create, empty dict when
+ # yardstick creates the template (no get_param in resources part)
+ if heat_parameters:
+ self.heat_parameters = heat_parameters
+
+ if template_file:
+ with open(template_file) as template:
+ print "Parsing external template:", template_file
+ template_str = template.read()
+ self._template = template_str
+ self._parameters = heat_parameters
else:
- base_template = template_dir + template_base_name
- new_template = template_dir + template_name
- new_template += "_" + str(counter) + template_extension
- shutil.copy(base_template, new_template)
-
- metadata = dict()
- for var in heat_template_vars:
- if var.get_variable_name():
- common.replace_in_file(new_template, "#" +
- var.get_variable_name(),
- var.get_variable_value())
- metadata[var.get_variable_name()] = var.get_variable_value()
-
- # Save the metadata on a JSON file
- with open(new_template + ".json", 'w') as outfile:
- json.dump(metadata, outfile)
-
- common.LOG.debug("Heat Templates and Metadata file " + str(counter) +
- " created")
- counter += 1
-
- # Creation of the template files
- common.LOG.info(str(counter - 1) + " Heat Templates and Metadata files "
- "created")
-
-
-def get_all_heat_templates(template_dir, template_extension):
- template_files = list()
- for dirname, dirnames, filenames in os.walk(template_dir):
- for filename in filenames:
- if template_extension in filename and filename.endswith(
- template_extension) and template_name in filename:
- template_files.append(filename)
- template_files.sort()
- return template_files
+ sys.exit("\nno such template file.")
+
+ # holds results of requested output after deployment
+ self.outputs = {}
+
+ log.debug("template object '%s' created", name)
+
+ def create(self, block=True):
+ '''creates a template in the target cloud using heat
+ returns a dict with the requested output values from the template'''
+ log.info("Creating stack '%s'", self.name)
+
+ # create stack early to support cleanup, e.g. ctrl-c while waiting
+ stack = HeatStack(self.name)
+
+ heat = self._get_heat_client()
+ end_time = start_time = time.time()
+ print(self._template)
+ stack.uuid = self.uuid = heat.stacks.create(
+ stack_name=self.name, template=self._template,
+ parameters=self.heat_parameters)['stack']['id']
+
+ status = self.status()
+
+ if block:
+ while status != u'CREATE_COMPLETE':
+ log.debug("stack state %s", status)
+ if status == u'CREATE_FAILED':
+ raise RuntimeError(getattr(heat.stacks.get(self.uuid),
+ 'stack_status_reason'))
+
+ time.sleep(2)
+ status = self.status()
+
+ end_time = time.time()
+ outputs = getattr(heat.stacks.get(self.uuid), 'outputs')
+
+ for output in outputs:
+ self.outputs[output["output_key"].encode("ascii")] = \
+ output["output_value"].encode("ascii")
+
+ log.info("Created stack '%s' in %d secs",
+ self.name, end_time - start_time)
+
+ stack.outputs = self.outputs
+ return stack