X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=yardstick%2Fbenchmark%2Fcontexts%2Fheat.py;h=cc87176d5a9ef32e0d487ef4b174b371bb4ac566;hb=da8e2c813048e70956e6dcb54b997e8e6bfb9ebf;hp=ff3e5f8014a573e766f42f5879040ed476cfd86d;hpb=a86ae455e2d8b3d3b09251b014d5c5d5f3dc8c9e;p=yardstick.git diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index ff3e5f801..cc87176d5 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -7,13 +7,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -from __future__ import print_function - import collections import logging import os -import uuid import errno from collections import OrderedDict @@ -25,9 +21,12 @@ from yardstick.benchmark.contexts.model import Network from yardstick.benchmark.contexts.model import PlacementGroup, ServerGroup from yardstick.benchmark.contexts.model import Server from yardstick.benchmark.contexts.model import update_scheduler_hints -from yardstick.common.openstack_utils import get_neutron_client -from yardstick.orchestrator.heat import HeatTemplate, get_short_key_uuid +from yardstick.common import exceptions as y_exc +from yardstick.common.openstack_utils import get_shade_client +from yardstick.orchestrator.heat import HeatStack +from yardstick.orchestrator.heat import HeatTemplate from yardstick.common import constants as consts +from yardstick.common import utils from yardstick.common.utils import source_env from yardstick.ssh import SSH @@ -50,7 +49,6 @@ class HeatContext(Context): __context_type__ = "Heat" def __init__(self): - self.name = None self.stack = None self.networks = OrderedDict() self.heat_timeout = None @@ -67,14 +65,9 @@ class HeatContext(Context): self._user = None self.template_file = None self.heat_parameters = None - self.neutron_client = None - # generate an uuid to identify yardstick_key - # the first 8 digits of the uuid will be used - self.key_uuid = uuid.uuid4() + self.shade_client = None self.heat_timeout = None - self.key_filename = ''.join( - [consts.YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-', - get_short_key_uuid(self.key_uuid)]) + self.key_filename = None super(HeatContext, self).__init__() @staticmethod @@ -95,13 +88,15 @@ class HeatContext(Context): return sorted_networks def init(self, attrs): - self.check_environment() - """initializes itself from the supplied arguments""" - self.name = attrs["name"] + """Initializes itself from the supplied arguments""" + super(HeatContext, self).init(attrs) + self.check_environment() self._user = attrs.get("user") self.template_file = attrs.get("heat_template") + + self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) if self.template_file: self.heat_parameters = attrs.get("heat_parameters") return @@ -113,8 +108,6 @@ class HeatContext(Context): self._flavor = attrs.get("flavor") - self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) - self.placement_groups = [PlacementGroup(name, self, pg_attrs["policy"]) for name, pg_attrs in attrs.get( "placement_groups", {}).items()] @@ -137,7 +130,6 @@ class HeatContext(Context): self._server_map[server.dn] = server self.attrs = attrs - SSH.gen_keys(self.key_filename) def check_environment(self): try: @@ -176,10 +168,13 @@ class HeatContext(Context): template.add_flavor(**self.flavor) self.flavors.add(flavor) - template.add_keypair(self.keypair_name, self.key_uuid) + template.add_keypair(self.keypair_name, self.name) template.add_security_group(self.secgroup_name) for network in self.networks.values(): + # Using existing network + if network.is_existing(): + continue template.add_network(network.stack_name, network.physical_network, network.provider, @@ -285,38 +280,67 @@ class HeatContext(Context): scheduler_hints) def get_neutron_info(self): - if not self.neutron_client: - self.neutron_client = get_neutron_client() + if not self.shade_client: + self.shade_client = get_shade_client() - networks = self.neutron_client.list_networks() + networks = self.shade_client.list_networks() for network in self.networks.values(): - for neutron_net in networks['networks']: - if neutron_net['name'] == network.stack_name: + for neutron_net in (net for net in networks if net.name == network.stack_name): network.segmentation_id = neutron_net.get('provider:segmentation_id') # we already have physical_network # network.physical_network = neutron_net.get('provider:physical_network') network.network_type = neutron_net.get('provider:network_type') network.neutron_info = neutron_net + def _create_new_stack(self, heat_template): + try: + return heat_template.create(block=True, + timeout=self.heat_timeout) + except KeyboardInterrupt: + raise y_exc.StackCreationInterrupt + except Exception: + LOG.exception("stack failed") + # let the other failures happen, we want stack trace + raise + + def _retrieve_existing_stack(self, stack_name): + stack = HeatStack(stack_name) + if stack.get(): + return stack + else: + LOG.warning("Stack %s does not exist", self.name) + return None + def deploy(self): """deploys template into a stack using cloud""" LOG.info("Deploying context '%s' START", self.name) - heat_template = HeatTemplate(self.name, self.template_file, - self.heat_parameters) + self.key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.name]) + # Permissions may have changed since creation; this can be fixed. If we + # overwrite the file, we lose future access to VMs using this key. + # As long as the file exists, even if it is unreadable, keep it intact + if not os.path.exists(self.key_filename): + SSH.gen_keys(self.key_filename) + + heat_template = HeatTemplate( + self.name, template_file=self.template_file, + heat_parameters=self.heat_parameters, + os_cloud_config=self._flags.os_cloud_config) if self.template_file is None: self._add_resources_to_template(heat_template) - try: - self.stack = heat_template.create(block=True, - timeout=self.heat_timeout) - except KeyboardInterrupt: - raise SystemExit("\nStack create interrupted") - except: - LOG.exception("stack failed") - # let the other failures happen, we want stack trace - raise + if self._flags.no_setup: + # Try to get an existing stack, returns a stack or None + self.stack = self._retrieve_existing_stack(self.name) + if not self.stack: + self.stack = self._create_new_stack(heat_template) + + else: + self.stack = self._create_new_stack(heat_template) # TODO: use Neutron to get segmentation-id self.get_neutron_info() @@ -332,22 +356,40 @@ class HeatContext(Context): LOG.info("Deploying context '%s' DONE", self.name) + @staticmethod + def _port_net_is_existing(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_EXISTING) + + @staticmethod + def _port_net_is_public(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_PUBLIC) + def add_server_port(self, server): - # use private ip from first port in first network - try: - private_port = next(iter(server.ports.values()))[0] - except IndexError: - LOG.exception("Unable to find first private port in %s", server.ports) - raise - server.private_ip = self.stack.outputs[private_port["stack_name"]] + server_ports = server.ports.values() + for server_port in server_ports: + port_info = server_port[0] + port_ip = self.stack.outputs[port_info["stack_name"]] + port_net_is_existing = self._port_net_is_existing(port_info) + port_net_is_public = self._port_net_is_public(port_info) + if port_net_is_existing and (port_net_is_public or + len(server_ports) == 1): + server.public_ip = port_ip + if not server.private_ip or len(server_ports) == 1: + server.private_ip = port_ip + server.interfaces = {} for network_name, ports in server.ports.items(): for port in ports: # port['port'] is either port name from mapping or default network_name + if self._port_net_is_existing(port): + continue server.interfaces[port['port']] = self.make_interface_dict(network_name, port['port'], port['stack_name'], self.stack.outputs) + server.override_ip(network_name, port) def make_interface_dict(self, network_name, port, stack_name, outputs): private_ip = outputs[stack_name] @@ -379,20 +421,27 @@ class HeatContext(Context): "local_ip": private_ip, } + def _delete_key_file(self): + try: + utils.remove_file(self.key_filename) + utils.remove_file(self.key_filename + ".pub") + except OSError: + LOG.exception("There was an error removing the key file %s", + self.key_filename) + def undeploy(self): """undeploys stack from cloud""" + if self._flags.no_teardown: + LOG.info("Undeploying context '%s' SKIP", self.name) + return + if self.stack: LOG.info("Undeploying context '%s' START", self.name) self.stack.delete() self.stack = None LOG.info("Undeploying context '%s' DONE", self.name) - if os.path.exists(self.key_filename): - try: - os.remove(self.key_filename) - os.remove(self.key_filename + ".pub") - except OSError: - LOG.exception("Key filename %s", self.key_filename) + self._delete_key_file() super(HeatContext, self).undeploy() @@ -416,7 +465,7 @@ class HeatContext(Context): with attribute name mapping when using external heat templates """ if isinstance(attr_name, collections.Mapping): - node_name, cname = self.split_name(attr_name['name']) + node_name, cname = self.split_host_name(attr_name['name']) if cname is None or cname != self.name: return None @@ -428,13 +477,17 @@ class HeatContext(Context): server.private_ip = self.stack.outputs.get( attr_name.get("private_ip_attr", object()), None) else: - server = self._server_map.get(attr_name, None) + try: + server = self._server_map[attr_name] + except KeyError: + attr_name_no_suffix = attr_name.split("-")[0] + server = self._server_map.get(attr_name_no_suffix, None) if server is None: return None pkey = pkg_resources.resource_string( 'yardstick.resources', - h_join('files/yardstick_key', get_short_key_uuid(self.key_uuid))).decode('utf-8') + h_join('files/yardstick_key', self.name)).decode('utf-8') result = { "user": server.context.user,