X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=yardstick%2Fbenchmark%2Fcontexts%2Fheat.py;h=c7586abf4586dff79e23e6c9fee1b0fd382f7660;hb=3016786696b9e5a26b364cb5bd4cb5676420fe58;hp=d5349eab580c361bae3a02456b80c56b15317c84;hpb=deccb02a8adabe609c2e903ce9f60e8b39db6c29;p=yardstick.git diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index d5349eab5..c7586abf4 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -14,10 +14,10 @@ import collections import logging import os import uuid +import errno from collections import OrderedDict import ipaddress -import paramiko import pkg_resources from yardstick.benchmark.contexts.base import Context @@ -27,13 +27,23 @@ 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.constants import YARDSTICK_ROOT_PATH +from yardstick.common import constants as consts +from yardstick.common.utils import source_env +from yardstick.ssh import SSH LOG = logging.getLogger(__name__) DEFAULT_HEAT_TIMEOUT = 3600 +def join_args(sep, *args): + return sep.join(args) + + +def h_join(*args): + return '-'.join(args) + + class HeatContext(Context): """Class that represents a context in the logical model""" @@ -43,12 +53,14 @@ class HeatContext(Context): self.name = None self.stack = None self.networks = OrderedDict() + self.heat_timeout = None self.servers = [] self.placement_groups = [] self.server_groups = [] self.keypair_name = None self.secgroup_name = None self._server_map = {} + self.attrs = {} self._image = None self._flavor = None self.flavors = set() @@ -61,23 +73,29 @@ class HeatContext(Context): self.key_uuid = uuid.uuid4() self.heat_timeout = None self.key_filename = ''.join( - [YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-', + [consts.YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-', get_short_key_uuid(self.key_uuid)]) super(HeatContext, self).__init__() - def assign_external_network(self, networks): + @staticmethod + def assign_external_network(networks): sorted_networks = sorted(networks.items()) external_network = os.environ.get("EXTERNAL_NETWORK", "net04_ext") have_external_network = any(net.get("external_network") for net in networks.values()) - if sorted_networks and not have_external_network: - # no external net defined, assign it to first network using os.environ - sorted_networks[0][1]["external_network"] = external_network + if not have_external_network: + # try looking for mgmt network first + try: + networks['mgmt']["external_network"] = external_network + except KeyError: + if sorted_networks: + # otherwise assign it to first network using os.environ + sorted_networks[0][1]["external_network"] = external_network - self.networks = OrderedDict((name, Network(name, self, attrs)) - for name, attrs in sorted_networks) + return sorted_networks def init(self, attrs): + self.check_environment() """initializes itself from the supplied arguments""" self.name = attrs["name"] @@ -88,8 +106,8 @@ class HeatContext(Context): self.heat_parameters = attrs.get("heat_parameters") return - self.keypair_name = self.name + "-key" - self.secgroup_name = self.name + "-secgroup" + self.keypair_name = h_join(self.name, "key") + self.secgroup_name = h_join(self.name, "secgroup") self._image = attrs.get("image") @@ -97,29 +115,42 @@ class HeatContext(Context): self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) - self.placement_groups = [PlacementGroup(name, self, pgattrs["policy"]) - for name, pgattrs in attrs.get( + self.placement_groups = [PlacementGroup(name, self, pg_attrs["policy"]) + for name, pg_attrs in attrs.get( "placement_groups", {}).items()] - self.server_groups = [ServerGroup(name, self, sgattrs["policy"]) - for name, sgattrs in attrs.get( + self.server_groups = [ServerGroup(name, self, sg_attrs["policy"]) + for name, sg_attrs in attrs.get( "server_groups", {}).items()] # we have to do this first, because we are injecting external_network # into the dict - self.assign_external_network(attrs["networks"]) + sorted_networks = self.assign_external_network(attrs["networks"]) - for name, serverattrs in sorted(attrs["servers"].items()): - server = Server(name, self, serverattrs) + self.networks = OrderedDict( + (name, Network(name, self, net_attrs)) for name, net_attrs in + sorted_networks) + + for name, server_attrs in sorted(attrs["servers"].items()): + server = Server(name, self, server_attrs) self.servers.append(server) self._server_map[server.dn] = server - rsa_key = paramiko.RSAKey.generate(bits=2048, progress_func=None) - rsa_key.write_private_key_file(self.key_filename) - print("Writing %s ..." % self.key_filename) - with open(self.key_filename + ".pub", "w") as pubkey_file: - pubkey_file.write( - "%s %s\n" % (rsa_key.get_name(), rsa_key.get_base64())) + self.attrs = attrs + SSH.gen_keys(self.key_filename) + + def check_environment(self): + try: + os.environ['OS_AUTH_URL'] + except KeyError: + try: + source_env(consts.OPENRC) + except IOError as e: + if e.errno != errno.EEXIST: + LOG.error('OPENRC file not found') + raise + else: + LOG.error('OS_AUTH_URL not found') @property def image(self): @@ -153,7 +184,8 @@ class HeatContext(Context): network.physical_network, network.provider, network.segmentation_id, - network.port_security_enabled) + network.port_security_enabled, + network.network_type) template.add_subnet(network.subnet_stack_name, network.stack_name, network.subnet_cidr, network.enable_dhcp, @@ -188,7 +220,7 @@ class HeatContext(Context): try: self.flavors.add(server.flavor["name"]) except KeyError: - self.flavors.add(server.stack_name + "-flavor") + self.flavors.add(h_join(server.stack_name, "flavor")) # add servers with availability policy added_servers = [] @@ -268,7 +300,7 @@ class HeatContext(Context): def deploy(self): """deploys template into a stack using cloud""" - print("Deploying context '%s'" % self.name) + LOG.info("Deploying context '%s' START", self.name) heat_template = HeatTemplate(self.name, self.template_file, self.heat_parameters) @@ -286,7 +318,7 @@ class HeatContext(Context): # let the other failures happen, we want stack trace raise - # TODO: use Neutron to get segementation-id + # TODO: use Neutron to get segmentation-id self.get_neutron_info() # copy some vital stack output into server objects @@ -298,48 +330,60 @@ class HeatContext(Context): server.public_ip = \ self.stack.outputs[server.floating_ip["stack_name"]] - print("Context '%s' deployed" % self.name) + LOG.info("Deploying context '%s' DONE", self.name) def add_server_port(self, server): - # TODO(hafe) can only handle one internal network for now - port = next(iter(server.ports.values())) - server.private_ip = self.stack.outputs[port["stack_name"]] + # 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.interfaces = {} - for network_name, port in server.ports.items(): - server.interfaces[network_name] = self.make_interface_dict( - network_name, port['stack_name'], self.stack.outputs) - - def make_interface_dict(self, network_name, stack_name, outputs): + for network_name, ports in server.ports.items(): + for port in ports: + # port['port'] is either port name from mapping or default network_name + server.interfaces[port['port']] = self.make_interface_dict(network_name, + port['port'], + port['stack_name'], + self.stack.outputs) + + def make_interface_dict(self, network_name, port, stack_name, outputs): private_ip = outputs[stack_name] - mac_addr = outputs[stack_name + "-mac_address"] - subnet_cidr_key = "-".join([self.name, network_name, 'subnet', 'cidr']) - gateway_key = "-".join([self.name, network_name, 'subnet', 'gateway_ip']) - subnet_cidr = outputs[subnet_cidr_key] - subnet_ip = ipaddress.ip_network(subnet_cidr) + mac_address = outputs[h_join(stack_name, "mac_address")] + # these are attributes of the network, not the port + output_subnet_cidr = outputs[h_join(self.name, network_name, + 'subnet', 'cidr')] + + # these are attributes of the network, not the port + output_subnet_gateway = outputs[h_join(self.name, network_name, + 'subnet', 'gateway_ip')] + return { "private_ip": private_ip, - "subnet_id": outputs[stack_name + "-subnet_id"], - "subnet_cidr": subnet_cidr, - "network": str(subnet_ip.network_address), - "netmask": str(subnet_ip.netmask), - "gateway_ip": outputs[gateway_key], - "mac_address": mac_addr, - "device_id": outputs[stack_name + "-device_id"], - "network_id": outputs[stack_name + "-network_id"], + "subnet_id": outputs[h_join(stack_name, "subnet_id")], + "subnet_cidr": output_subnet_cidr, + "network": str(ipaddress.ip_network(output_subnet_cidr).network_address), + "netmask": str(ipaddress.ip_network(output_subnet_cidr).netmask), + "gateway_ip": output_subnet_gateway, + "mac_address": mac_address, + "device_id": outputs[h_join(stack_name, "device_id")], + "network_id": outputs[h_join(stack_name, "network_id")], + # this should be == vld_id for NSB tests "network_name": network_name, # to match vnf_generic - "local_mac": mac_addr, + "local_mac": mac_address, "local_ip": private_ip, - "vld_id": self.networks[network_name].vld_id, } def undeploy(self): """undeploys stack from cloud""" if self.stack: - print("Undeploying context '%s'" % self.name) + LOG.info("Undeploying context '%s' START", self.name) self.stack.delete() self.stack = None - print("Context '%s' undeployed" % self.name) + LOG.info("Undeploying context '%s' DONE", self.name) if os.path.exists(self.key_filename): try: @@ -357,7 +401,8 @@ class HeatContext(Context): "network": intf["network"], "netmask": intf["netmask"], "if": name, - "gateway": intf["gateway_ip"], + # We have to encode a None gateway as '' for Jinja2 to YAML conversion + "gateway": intf["gateway_ip"] if intf["gateway_ip"] else '', } for name, intf in server.interfaces.items() ] @@ -370,31 +415,24 @@ class HeatContext(Context): """ key_filename = pkg_resources.resource_filename( 'yardstick.resources', - 'files/yardstick_key-' + get_short_key_uuid(self.key_uuid)) + h_join('files/yardstick_key', get_short_key_uuid(self.key_uuid))) - if not isinstance(attr_name, collections.Mapping): - server = self._server_map.get(attr_name, None) - - else: - cname = attr_name["name"].split(".")[1] - if cname != self.name: + if isinstance(attr_name, collections.Mapping): + node_name, cname = self.split_name(attr_name['name']) + if cname is None or cname != self.name: return None - public_ip = None - private_ip = None - if "public_ip_attr" in attr_name: - public_ip = self.stack.outputs[attr_name["public_ip_attr"]] - if "private_ip_attr" in attr_name: - private_ip = self.stack.outputs[ - attr_name["private_ip_attr"]] - # Create a dummy server instance for holding the *_ip attributes - server = Server(attr_name["name"].split(".")[0], self, {}) - server.public_ip = public_ip - server.private_ip = private_ip + server = Server(node_name, self, {}) + server.public_ip = self.stack.outputs.get( + attr_name.get("public_ip_attr", object()), None) - if server is None: - return None + server.private_ip = self.stack.outputs.get( + attr_name.get("private_ip_attr", object()), None) + else: + server = self._server_map.get(attr_name, None) + if server is None: + return None result = { "user": server.context.user, @@ -416,20 +454,18 @@ class HeatContext(Context): network = self.networks.get(attr_name, None) else: - # Don't generalize too much Just support vld_id - vld_id = attr_name.get('vld_id') - if vld_id is None: + # Only take the first key, value + key, value = next(iter(attr_name.items()), (None, None)) + if key is None: return None - - network = next((n for n in self.networks.values() if - getattr(n, "vld_id", None) == vld_id), None) + network_iter = (n for n in self.networks.values() if getattr(n, key) == value) + network = next(network_iter, None) if network is None: return None result = { "name": network.name, - "vld_id": network.vld_id, "segmentation_id": network.segmentation_id, "network_type": network.network_type, "physical_network": network.physical_network,