diff options
-rw-r--r-- | api/resources/env_action.py | 3 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/test_heat.py | 9 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/test_model.py | 10 | ||||
-rw-r--r-- | tests/unit/cmd/test_NSBperf.py | 3 | ||||
-rw-r--r-- | tests/unit/common/test_openstack_utils.py | 28 | ||||
-rw-r--r-- | yardstick/__init__.py | 13 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/heat.py | 37 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/model.py | 43 | ||||
-rw-r--r-- | yardstick/benchmark/core/task.py | 6 | ||||
-rwxr-xr-x | yardstick/cmd/NSBperf.py | 7 | ||||
-rw-r--r-- | yardstick/cmd/cli.py | 13 | ||||
-rw-r--r-- | yardstick/common/openstack_utils.py | 348 | ||||
-rw-r--r-- | yardstick/common/utils.py | 17 | ||||
-rw-r--r-- | yardstick/orchestrator/heat.py | 10 |
15 files changed, 473 insertions, 76 deletions
diff --git a/api/resources/env_action.py b/api/resources/env_action.py index 2d3496cbc..ea94bc123 100644 --- a/api/resources/env_action.py +++ b/api/resources/env_action.py @@ -27,6 +27,7 @@ from api.utils.common import result_handler from docker import Client from yardstick.common import constants as config from yardstick.common import utils as yardstick_utils +from yardstick.common import openstack_utils from yardstick.common.httpClient import HttpClient logger = logging.getLogger(__name__) @@ -263,7 +264,7 @@ def _get_remote_rc_file(rc_file, installer_ip, installer_type): def _append_external_network(rc_file): - neutron_client = yardstick_utils.get_neutron_client() + neutron_client = openstack_utils.get_neutron_client() networks = neutron_client.list_networks()['networks'] try: ext_network = next(n['name'] for n in networks if n['router:external']) diff --git a/requirements.txt b/requirements.txt index d04824686..3549f85e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,7 +44,7 @@ oslo.config==3.9.0 oslo.i18n==3.4.0 oslo.serialization==2.4.0 oslo.utils==3.7.0 -paramiko==1.16.0 +paramiko==1.18.0 pbr==1.8.1 pep8==1.7.0 positional==1.0.1 diff --git a/tests/unit/benchmark/contexts/test_heat.py b/tests/unit/benchmark/contexts/test_heat.py index f8f349205..8f4852ca8 100644 --- a/tests/unit/benchmark/contexts/test_heat.py +++ b/tests/unit/benchmark/contexts/test_heat.py @@ -39,6 +39,7 @@ class HeatContextTestCase(unittest.TestCase): self.assertEqual(self.test_context.networks, []) self.assertEqual(self.test_context.servers, []) self.assertEqual(self.test_context.placement_groups, []) + self.assertEqual(self.test_context.server_groups, []) self.assertIsNone(self.test_context.keypair_name) self.assertIsNone(self.test_context.secgroup_name) self.assertEqual(self.test_context._server_map, {}) @@ -51,15 +52,18 @@ class HeatContextTestCase(unittest.TestCase): self.assertIsNotNone(self.test_context.key_filename) @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup') + @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup') @mock.patch('yardstick.benchmark.contexts.heat.Network') @mock.patch('yardstick.benchmark.contexts.heat.Server') - def test_init(self, mock_server, mock_network, mock_pg): + def test_init(self, mock_server, mock_network, mock_sg, mock_pg): pgs = {'pgrp1': {'policy': 'availability'}} + sgs = {'servergroup1': {'policy': 'affinity'}} networks = {'bar': {'cidr': '10.0.1.0/24'}} servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}} attrs = {'name': 'foo', 'placement_groups': pgs, + 'server_groups': sgs, 'networks': networks, 'servers': servers} @@ -71,7 +75,10 @@ class HeatContextTestCase(unittest.TestCase): mock_pg.assert_called_with('pgrp1', self.test_context, pgs['pgrp1']['policy']) + mock_sg.assert_called_with('servergroup1', self.test_context, + sgs['servergroup1']['policy']) self.assertTrue(len(self.test_context.placement_groups) == 1) + self.assertTrue(len(self.test_context.server_groups) == 1) mock_network.assert_called_with( 'bar', self.test_context, networks['bar']) diff --git a/tests/unit/benchmark/contexts/test_model.py b/tests/unit/benchmark/contexts/test_model.py index 537a8c008..a4b7d81ef 100644 --- a/tests/unit/benchmark/contexts/test_model.py +++ b/tests/unit/benchmark/contexts/test_model.py @@ -180,6 +180,7 @@ class ServerTestCase(unittest.TestCase): self.assertEqual(test_server.keypair_name, 'some-keys') self.assertEqual(test_server.secgroup_name, 'some-secgroup') self.assertEqual(test_server.placement_groups, []) + self.assertIsNone(test_server.server_group) self.assertEqual(test_server.instances, 1) self.assertIsNone(test_server.floating_ip) self.assertIsNone(test_server._image) @@ -195,6 +196,15 @@ class ServerTestCase(unittest.TestCase): self.assertRaises(ValueError, model.Server, 'foo', self.mock_context, attrs) + @mock.patch('yardstick.benchmark.contexts.model.PlacementGroup') + def test_construct_get_wrong_server_group(self, mock_sg): + + attrs = {'server_group': 'baz'} + mock_sg.get.return_value = None + + self.assertRaises(ValueError, model.Server, 'foo', + self.mock_context, attrs) + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test__add_instance(self, mock_template): diff --git a/tests/unit/cmd/test_NSBperf.py b/tests/unit/cmd/test_NSBperf.py index a14c08464..5bd248a84 100644 --- a/tests/unit/cmd/test_NSBperf.py +++ b/tests/unit/cmd/test_NSBperf.py @@ -40,7 +40,8 @@ class TestYardstickNSCli(unittest.TestCase): def test_generate_final_report(self): yardstick_ns_cli = YardstickNSCli() test_case = "tc_baremetal_rfc2544_ipv4_1flow_1518B.yaml" - subprocess.call(["touch", "/tmp/yardstick.out"]) + if os.path.isfile("/tmp/yardstick.out"): + os.remove('/tmp/yardstick.out') self.assertIsNone(yardstick_ns_cli.generate_final_report(test_case)) def test_generate_kpi_results(self): diff --git a/tests/unit/common/test_openstack_utils.py b/tests/unit/common/test_openstack_utils.py index d610e181c..b3dc2d9c4 100644 --- a/tests/unit/common/test_openstack_utils.py +++ b/tests/unit/common/test_openstack_utils.py @@ -22,21 +22,25 @@ class GetCredentialsTestCase(unittest.TestCase): @mock.patch('yardstick.common.openstack_utils.os') def test_get_credentials(self, mock_os): - mock_os.getenv.return_value = ('2') - openstack_utils.get_credentials() + with mock.patch.dict('os.environ', {'OS_IDENTITY_API_VERSION': '2'}, + clear=True): + openstack_utils.get_credentials() class GetHeatApiVersionTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.os') - def test_get_heat_api_version(self, mock_os): + def test_get_heat_api_version_check_result(self): API = 'HEAT_API_VERSION' - openstack_utils.get_heat_api_version() - mock_os.getenv.assert_called_with(API) - - @mock.patch('yardstick.common.openstack_utils.os') - def test_get_heat_api_version(self, mock_os): - mock_os.getenv.return_value = ('2') expected_result = '2' - api_version = openstack_utils.get_heat_api_version() - self.assertEqual(api_version, expected_result) + + with mock.patch.dict('os.environ', {API: '2'}, clear=True): + api_version = openstack_utils.get_heat_api_version() + self.assertEqual(api_version, expected_result) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/__init__.py b/yardstick/__init__.py index 1ad6eb0b1..e19be36fd 100644 --- a/yardstick/__init__.py +++ b/yardstick/__init__.py @@ -35,19 +35,18 @@ LOG = logging.getLogger(__name__) def _init_logging(): - _LOG_STREAM_HDLR.setFormatter(_LOG_FORMATTER) + LOG.setLevel(logging.DEBUG) + _LOG_STREAM_HDLR.setFormatter(_LOG_FORMATTER) + if os.environ.get('CI_DEBUG', '').lower() in {'1', 'y', "yes", "true"}: + _LOG_STREAM_HDLR.setLevel(logging.DEBUG) + else: + _LOG_STREAM_HDLR.setLevel(logging.INFO) # don't append to log file, clobber _LOG_FILE_HDLR.setFormatter(_LOG_FORMATTER) - # set log file to store debug info _LOG_FILE_HDLR.setLevel(logging.DEBUG) del logging.root.handlers[:] logging.root.addHandler(_LOG_STREAM_HDLR) logging.root.addHandler(_LOG_FILE_HDLR) logging.debug("logging.root.handlers = %s", logging.root.handlers) - - if os.environ.get('CI_DEBUG', '').lower() in {'1', 1, 'y', "yes", "true"}: - LOG.setLevel(logging.DEBUG) - else: - LOG.setLevel(logging.INFO) diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 4ca44b0ed..c5c127966 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -21,7 +21,7 @@ import pkg_resources from yardstick.benchmark.contexts.base import Context from yardstick.benchmark.contexts.model import Network -from yardstick.benchmark.contexts.model import PlacementGroup +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.orchestrator.heat import HeatTemplate, get_short_key_uuid @@ -41,6 +41,7 @@ class HeatContext(Context): self.networks = [] self.servers = [] self.placement_groups = [] + self.server_groups = [] self.keypair_name = None self.secgroup_name = None self._server_map = {} @@ -57,7 +58,7 @@ class HeatContext(Context): get_short_key_uuid(self.key_uuid)]) super(HeatContext, self).__init__() - def init(self, attrs): + def init(self, attrs): # pragma: no cover """initializes itself from the supplied arguments""" self.name = attrs["name"] @@ -73,15 +74,18 @@ class HeatContext(Context): self.secgroup_name = self.name + "-secgroup" if "image" in attrs: - self._image = attrs["image"] + self._image = attrs.get("image") if "flavor" in attrs: - self._flavor = attrs["flavor"] + self._flavor = attrs.get("flavor") - if "placement_groups" in attrs: - for name, pgattrs in attrs["placement_groups"].items(): - pg = PlacementGroup(name, self, pgattrs["policy"]) - self.placement_groups.append(pg) + self.placement_groups = [PlacementGroup(name, self, pgattrs["policy"]) + for name, pgattrs in attrs.get( + "placement_groups", {}).items()] + + self.server_groups = [ServerGroup(name, self, sgattrs["policy"]) + for name, sgattrs in attrs.get( + "server_groups", {}).items()] for name, netattrs in attrs["networks"].items(): network = Network(name, self, netattrs) @@ -163,19 +167,17 @@ class HeatContext(Context): server.add_to_template(template, self.networks, scheduler_hints) - added_servers.append(server.stack_name) else: scheduler_hints["different_host"] = \ scheduler_hints["different_host"][0] server.add_to_template(template, self.networks, scheduler_hints) - added_servers.append(server.stack_name) else: server.add_to_template(template, self.networks, scheduler_hints) - added_servers.append(server.stack_name) + added_servers.append(server.stack_name) # create list of servers with affinity policy affinity_servers = [] @@ -195,10 +197,21 @@ class HeatContext(Context): server.add_to_template(template, self.networks, scheduler_hints) added_servers.append(server.stack_name) + # add server group + for sg in self.server_groups: + template.add_server_group(sg.name, sg.policy) + # add remaining servers with no placement group configured for server in list_of_servers: + # TODO placement_group and server_group should combine if not server.placement_groups: - server.add_to_template(template, self.networks, {}) + scheduler_hints = {} + # affinity/anti-aff server group + sg = server.server_group + if sg: + scheduler_hints["group"] = {'get_resource': sg.name} + server.add_to_template(template, + self.networks, scheduler_hints) def deploy(self): """deploys template into a stack using cloud""" diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index c83a209cf..8cf3b621c 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -56,10 +56,32 @@ class PlacementGroup(Object): @staticmethod def get(name): - if name in PlacementGroup.map: - return PlacementGroup.map[name] - else: - return None + return PlacementGroup.map.get(name) + + +class ServerGroup(Object): # pragma: no cover + """Class that represents a server group in the logical model + Policy should be one of "anti-affinity" or "affinity" + """ + map = {} + + def __init__(self, name, context, policy): + super(ServerGroup, self).__init__(name, context) + if policy not in {"affinity", "anti-affinity"}: + raise ValueError("server group '%s', policy '%s' is not valid" % + (name, policy)) + self.name = name + self.members = set() + self.stack_name = context.name + "-" + name + self.policy = policy + ServerGroup.map[name] = self + + def add_member(self, name): + self.members.add(name) + + @staticmethod + def get(name): + return ServerGroup.map.get(name) class Router(Object): @@ -113,7 +135,7 @@ class Network(Object): return None -class Server(Object): +class Server(Object): # pragma: no cover """Class that represents a server in the logical model""" list = [] @@ -141,6 +163,17 @@ class Server(Object): self.placement_groups.append(pg) pg.add_member(self.stack_name) + # support servergroup attr + self.server_group = None + sg = attrs.get("server_group") + if (sg): + server_group = ServerGroup.get(sg) + if not server_group: + raise ValueError("server '%s', server_group '%s' is invalid" % + (name, sg)) + self.server_group = server_group + server_group.add_member(self.stack_name) + self.instances = 1 if "instances" in attrs: self.instances = attrs["instances"] diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 522ad4d23..aecf5bf4a 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -267,7 +267,11 @@ class TaskParser(object): # pragma: no cover name_suffix = '-{}'.format(task_id[:8]) for cfg_attrs in context_cfgs: - cfg_attrs['name'] = '{}{}'.format(cfg_attrs['name'], name_suffix) + try: + cfg_attrs['name'] = '{}{}'.format(cfg_attrs['name'], + name_suffix) + except KeyError: + pass context_type = cfg_attrs.get("type", "Heat") if "Heat" == context_type and "networks" in cfg_attrs: # bugfix: if there are more than one network, diff --git a/yardstick/cmd/NSBperf.py b/yardstick/cmd/NSBperf.py index c3730f834..f158d57f4 100755 --- a/yardstick/cmd/NSBperf.py +++ b/yardstick/cmd/NSBperf.py @@ -24,7 +24,7 @@ import argparse import json import subprocess import signal - +from oslo_serialization import jsonutils from six.moves import input @@ -126,10 +126,11 @@ class YardstickNSCli(object): if os.path.isfile("/tmp/yardstick.out"): lines = [] with open("/tmp/yardstick.out") as infile: - lines = infile.readlines() + lines = jsonutils.load(infile) if lines: - tc_res = json.loads(lines.pop(len(lines) - 1)) + lines = lines['result'] + tc_res = lines.pop(len(lines) - 1) for key, value in tc_res["benchmark"]["data"].items(): self.generate_kpi_results(key, value) self.generate_nfvi_results(value) diff --git a/yardstick/cmd/cli.py b/yardstick/cmd/cli.py index 6281bb813..1f8dfee2d 100644 --- a/yardstick/cmd/cli.py +++ b/yardstick/cmd/cli.py @@ -20,7 +20,7 @@ from pkg_resources import get_distribution from argparse import RawDescriptionHelpFormatter from oslo_config import cfg -from yardstick import _init_logging, LOG +from yardstick import _init_logging, _LOG_STREAM_HDLR from yardstick.cmd.commands import task from yardstick.cmd.commands import runner from yardstick.cmd.commands import scenario @@ -33,11 +33,7 @@ cli_opts = [ cfg.BoolOpt('debug', short='d', default=False, - help='increase output verbosity to debug'), - cfg.BoolOpt('verbose', - short='v', - default=False, - help='increase output verbosity to info') + help='increase output verbosity to debug') ] CONF.register_cli_opts(cli_opts) @@ -132,11 +128,8 @@ class YardstickCLI(): def _handle_global_opts(self): _init_logging() - if CONF.verbose: - LOG.setLevel(logging.INFO) - if CONF.debug: - LOG.setLevel(logging.DEBUG) + _LOG_STREAM_HDLR.setLevel(logging.DEBUG) def _dispath_func_notask(self): diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index 5026e819d..aa369b896 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -8,17 +8,26 @@ ############################################################################## from __future__ import absolute_import + import os +import time import logging from keystoneauth1 import loading from keystoneauth1 import session +from novaclient import client as novaclient +from glanceclient import client as glanceclient +from neutronclient.neutron import client as neutronclient log = logging.getLogger(__name__) DEFAULT_HEAT_API_VERSION = '1' +DEFAULT_API_VERSION = '2' +# ********************************************* +# CREDENTIALS +# ********************************************* def get_credentials(): """Returns a creds dictionary filled with parsed from env""" creds = {} @@ -64,7 +73,7 @@ def get_credentials(): "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\ + log.info("WARNING: The 'OS_CACERT' environment variable is set \ to %s but the file does not exist.", cacert) return creds @@ -89,9 +98,338 @@ def get_endpoint(service_type, endpoint_type='publicURL'): endpoint_type=endpoint_type) -def get_heat_api_version(): - api_version = os.getenv('HEAT_API_VERSION') - if api_version is not None: +# ********************************************* +# CLIENTS +# ********************************************* +def get_heat_api_version(): # pragma: no cover + try: + api_version = os.environ['HEAT_API_VERSION'] + except KeyError: + return DEFAULT_HEAT_API_VERSION + else: log.info("HEAT_API_VERSION is set in env as '%s'", api_version) return api_version - return DEFAULT_HEAT_API_VERSION + + +def get_nova_client_version(): # pragma: no cover + try: + api_version = os.environ['OS_COMPUTE_API_VERSION'] + except KeyError: + return DEFAULT_API_VERSION + else: + log.info("OS_COMPUTE_API_VERSION is set in env as '%s'", api_version) + return api_version + + +def get_nova_client(): # pragma: no cover + sess = get_session() + return novaclient.Client(get_nova_client_version(), session=sess) + + +def get_neutron_client_version(): # pragma: no cover + try: + api_version = os.environ['OS_NETWORK_API_VERSION'] + except KeyError: + return DEFAULT_API_VERSION + else: + log.info("OS_NETWORK_API_VERSION is set in env as '%s'", api_version) + return api_version + + +def get_neutron_client(): # pragma: no cover + sess = get_session() + return neutronclient.Client(get_neutron_client_version(), session=sess) + + +def get_glance_client_version(): # pragma: no cover + try: + api_version = os.environ['OS_IMAGE_API_VERSION'] + except KeyError: + return DEFAULT_API_VERSION + else: + log.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version) + return api_version + + +def get_glance_client(): # pragma: no cover + sess = get_session() + return glanceclient.Client(get_glance_client_version(), session=sess) + + +# ********************************************* +# NOVA +# ********************************************* +def get_instances(nova_client): # pragma: no cover + try: + return nova_client.servers.list(search_opts={'all_tenants': 1}) + except Exception: + log.exception("Error [get_instances(nova_client)]") + + +def get_instance_status(nova_client, instance): # pragma: no cover + try: + return nova_client.servers.get(instance.id).status + except Exception: + log.exception("Error [get_instance_status(nova_client)]") + + +def get_instance_by_name(nova_client, instance_name): # pragma: no cover + try: + return nova_client.servers.find(name=instance_name) + except Exception: + log.exception("Error [get_instance_by_name(nova_client, '%s')]", + instance_name) + + +def get_aggregates(nova_client): # pragma: no cover + try: + return nova_client.aggregates.list() + except Exception: + log.exception("Error [get_aggregates(nova_client)]") + + +def get_availability_zones(nova_client): # pragma: no cover + try: + return nova_client.availability_zones.list() + except Exception: + log.exception("Error [get_availability_zones(nova_client)]") + + +def get_availability_zone_names(nova_client): # pragma: no cover + try: + return [az.zoneName for az in get_availability_zones(nova_client)] + except Exception: + log.exception("Error [get_availability_zone_names(nova_client)]") + + +def create_aggregate(nova_client, aggregate_name, av_zone): # pragma: no cover + try: + nova_client.aggregates.create(aggregate_name, av_zone) + except Exception: + log.exception("Error [create_aggregate(nova_client, %s, %s)]", + aggregate_name, av_zone) + return False + else: + return True + + +def get_aggregate_id(nova_client, aggregate_name): # pragma: no cover + try: + aggregates = get_aggregates(nova_client) + _id = next((ag.id for ag in aggregates if ag.name == aggregate_name)) + except Exception: + log.exception("Error [get_aggregate_id(nova_client, %s)]", + aggregate_name) + else: + return _id + + +def add_host_to_aggregate(nova_client, aggregate_name, + compute_host): # pragma: no cover + try: + aggregate_id = get_aggregate_id(nova_client, aggregate_name) + nova_client.aggregates.add_host(aggregate_id, compute_host) + except Exception: + log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]", + aggregate_name, compute_host) + return False + else: + return True + + +def create_aggregate_with_host(nova_client, aggregate_name, av_zone, + compute_host): # pragma: no cover + try: + create_aggregate(nova_client, aggregate_name, av_zone) + add_host_to_aggregate(nova_client, aggregate_name, compute_host) + except Exception: + log.exception("Error [create_aggregate_with_host(" + "nova_client, %s, %s, %s)]", + aggregate_name, av_zone, compute_host) + return False + else: + return True + + +def create_instance(flavor_name, + image_id, + network_id, + instance_name="instance-vm", + confdrive=True, + userdata=None, + av_zone='', + fixed_ip=None, + files=None): # pragma: no cover + nova_client = get_nova_client() + try: + flavor = nova_client.flavors.find(name=flavor_name) + except: + flavors = nova_client.flavors.list() + log.exception("Error: Flavor '%s' not found. Available flavors are: " + "\n%s", flavor_name, flavors) + return None + if fixed_ip is not None: + nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip} + else: + nics = {"net-id": network_id} + if userdata is None: + instance = nova_client.servers.create( + name=instance_name, + flavor=flavor, + image=image_id, + nics=[nics], + availability_zone=av_zone, + files=files + ) + else: + instance = nova_client.servers.create( + name=instance_name, + flavor=flavor, + image=image_id, + nics=[nics], + config_drive=confdrive, + userdata=userdata, + availability_zone=av_zone, + files=files + ) + return instance + + +def create_instance_and_wait_for_active(flavor_name, + image_id, + network_id, + instance_name="instance-vm", + config_drive=False, + userdata="", + av_zone='', + fixed_ip=None, + files=None): # pragma: no cover + SLEEP = 3 + VM_BOOT_TIMEOUT = 180 + nova_client = get_nova_client() + instance = create_instance(flavor_name, + image_id, + network_id, + instance_name, + config_drive, + userdata, + av_zone=av_zone, + fixed_ip=fixed_ip, + files=files) + count = VM_BOOT_TIMEOUT / SLEEP + for n in range(count, -1, -1): + status = get_instance_status(nova_client, instance) + if status.lower() == "active": + return instance + elif status.lower() == "error": + log.error("The instance %s went to ERROR status.", instance_name) + return None + time.sleep(SLEEP) + log.error("Timeout booting the instance %s.", instance_name) + return None + + +def delete_instance(nova_client, instance_id): # pragma: no cover + try: + nova_client.servers.force_delete(instance_id) + except Exception: + log.exception("Error [delete_instance(nova_client, '%s')]", + instance_id) + return False + else: + return True + + +def remove_host_from_aggregate(nova_client, aggregate_name, + compute_host): # pragma: no cover + try: + aggregate_id = get_aggregate_id(nova_client, aggregate_name) + nova_client.aggregates.remove_host(aggregate_id, compute_host) + except Exception: + log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)", + aggregate_name, compute_host) + return False + else: + return True + + +def remove_hosts_from_aggregate(nova_client, + aggregate_name): # pragma: no cover + aggregate_id = get_aggregate_id(nova_client, aggregate_name) + hosts = nova_client.aggregates.get(aggregate_id).hosts + assert( + all(remove_host_from_aggregate(nova_client, aggregate_name, host) + for host in hosts)) + + +def delete_aggregate(nova_client, aggregate_name): # pragma: no cover + try: + remove_hosts_from_aggregate(nova_client, aggregate_name) + nova_client.aggregates.delete(aggregate_name) + except Exception: + log.exception("Error [delete_aggregate(nova_client, %s)]", + aggregate_name) + return False + else: + return True + + +def get_server_by_name(name): # pragma: no cover + try: + return get_nova_client().servers.list(search_opts={'name': name})[0] + except IndexError: + log.exception('Failed to get nova client') + raise + + +def get_image_by_name(name): # pragma: no cover + images = get_nova_client().images.list() + try: + return next((a for a in images if a.name == name)) + except StopIteration: + log.exception('No image matched') + + +def get_flavor_by_name(name): # pragma: no cover + flavors = get_nova_client().flavors.list() + try: + return next((a for a in flavors if a.name == name)) + except StopIteration: + log.exception('No flavor matched') + + +def check_status(status, name, iterations, interval): # pragma: no cover + for i in range(iterations): + try: + server = get_server_by_name(name) + except IndexError: + log.error('Cannot found %s server', name) + raise + + if server.status == status: + return True + + time.sleep(interval) + return False + + +# ********************************************* +# NEUTRON +# ********************************************* +def get_network_id(neutron_client, network_name): # pragma: no cover + networks = neutron_client.list_networks()['networks'] + return next((n['id'] for n in networks if n['name'] == network_name), None) + + +def get_port_id_by_ip(neutron_client, ip_address): # pragma: no cover + ports = neutron_client.list_ports()['ports'] + return next((i['id'] for i in ports for j in i.get( + 'fixed_ips') if j['ip_address'] == ip_address), None) + + +# ********************************************* +# GLANCE +# ********************************************* +def get_image_id(glance_client, image_name): # pragma: no cover + images = glance_client.images.list() + return next((i.id for i in images if i.name == image_name), None) diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 04536190b..3c5895f1e 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -26,9 +26,6 @@ import sys from functools import reduce import yaml -from keystoneauth1 import identity -from keystoneauth1 import session -from neutronclient.v2_0 import client from oslo_utils import importutils from oslo_serialization import jsonutils @@ -134,20 +131,6 @@ def source_env(env_file): return env -def get_openstack_session(): - auth = identity.Password(auth_url=os.environ.get('OS_AUTH_URL'), - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD'), - tenant_name=os.environ.get('OS_TENANT_NAME')) - return session.Session(auth=auth) - - -def get_neutron_client(): - sess = get_openstack_session() - neutron_client = client.Client(session=sess) - return neutron_client - - def read_json_from_file(path): with open(path, 'r') as f: return jsonutils.load(f) diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index e39c4356c..500776e0e 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -197,6 +197,16 @@ class HeatTemplate(HeatObject): 'properties': {'name': name} } + def add_server_group(self, name, policies): # pragma: no cover + """add to the template a ServerGroup""" + log.debug("adding Nova::ServerGroup '%s'", name) + policies = policies if isinstance(policies, list) else [policies] + self.resources[name] = { + 'type': 'OS::Nova::ServerGroup', + 'properties': {'name': name, + 'policies': policies} + } + def add_subnet(self, name, network, cidr): """add to the template a Neutron Subnet""" log.debug("adding Neutron::Subnet '%s' in network '%s', cidr '%s'", |