From 2e3974f99811dda12ca3f7e3a9521a0efc2e8677 Mon Sep 17 00:00:00 2001 From: JingLu5 Date: Mon, 21 Aug 2017 02:44:17 +0000 Subject: [PATCH] Add common openstack opertation scenarios: subnet & port JIRA: YARDSTICK-781 This patch adds some common openstack opertation scenarios Change-Id: Ie59f0d5ae0842f8347824c961436b889a95b1a72 Signed-off-by: JingLu5 --- .../benchmark/scenarios/lib/test_create_network.py | 39 ++++++ .../benchmark/scenarios/lib/test_create_port.py | 36 ++++++ .../benchmark/scenarios/lib/test_create_router.py | 39 ++++++ .../scenarios/lib/test_create_sec_group.py | 39 ++++++ .../benchmark/scenarios/lib/test_create_subnet.py | 41 ++++++ .../benchmark/scenarios/lib/create_keypair.py | 2 + .../benchmark/scenarios/lib/create_network.py | 64 +++++++++ yardstick/benchmark/scenarios/lib/create_port.py | 66 ++++++++++ yardstick/benchmark/scenarios/lib/create_router.py | 66 ++++++++++ .../benchmark/scenarios/lib/create_sec_group.py | 65 ++++++++++ yardstick/benchmark/scenarios/lib/create_server.py | 2 + yardstick/benchmark/scenarios/lib/create_subnet.py | 66 ++++++++++ yardstick/common/openstack_utils.py | 144 +++++++++++++++++++++ 13 files changed, 669 insertions(+) create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_network.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_port.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_router.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_sec_group.py create mode 100644 tests/unit/benchmark/scenarios/lib/test_create_subnet.py create mode 100644 yardstick/benchmark/scenarios/lib/create_network.py create mode 100644 yardstick/benchmark/scenarios/lib/create_port.py create mode 100644 yardstick/benchmark/scenarios/lib/create_router.py create mode 100644 yardstick/benchmark/scenarios/lib/create_sec_group.py create mode 100644 yardstick/benchmark/scenarios/lib/create_subnet.py diff --git a/tests/unit/benchmark/scenarios/lib/test_create_network.py b/tests/unit/benchmark/scenarios/lib/test_create_network.py new file mode 100644 index 000000000..8e7d8b5a1 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_network.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_network import CreateNetwork + + +class CreateNetworkTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + @mock.patch('yardstick.common.openstack_utils.create_neutron_net') + def test_create_network(self, mock_get_neutron_client, mock_create_neutron_net): + options = { + 'openstack_paras': { + 'name': 'yardstick_net', + 'admin_state_up': 'True' + } + } + args = {"options": options} + obj = CreateNetwork(args, {}) + obj.run({}) + self.assertTrue(mock_get_neutron_client.called) + self.assertTrue(mock_create_neutron_net.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_port.py b/tests/unit/benchmark/scenarios/lib/test_create_port.py new file mode 100644 index 000000000..3b2aa2247 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_port.py @@ -0,0 +1,36 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_port import CreatePort + + +class CreatePortTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + def test_create_port(self, mock_get_neutron_client): + options = { + 'openstack_paras': { + 'name': 'yardstick_port' + } + } + args = {"options": options} + obj = CreatePort(args, {}) + obj.run({}) + self.assertTrue(mock_get_neutron_client.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_router.py b/tests/unit/benchmark/scenarios/lib/test_create_router.py new file mode 100644 index 000000000..b956a3634 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_router.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_router import CreateRouter + + +class CreateRouterTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + @mock.patch('yardstick.common.openstack_utils.create_neutron_router') + def test_create_router(self, mock_get_neutron_client, mock_create_neutron_router): + options = { + 'openstack_paras': { + 'admin_state_up': 'True', + 'name': 'yardstick_router' + } + } + args = {"options": options} + obj = CreateRouter(args, {}) + obj.run({}) + self.assertTrue(mock_get_neutron_client.called) + self.assertTrue(mock_create_neutron_router.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py b/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py new file mode 100644 index 000000000..b962f7f0e --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_sec_group import CreateSecgroup + + +class CreateSecGroupTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + @mock.patch('yardstick.common.openstack_utils.create_security_group_full') + def test_create_sec_group(self, mock_get_neutron_client, mock_create_security_group_full): + options = { + 'openstack_paras': { + 'sg_name': 'yardstick_sec_group', + 'description': 'security group for yardstick manual VM' + } + } + args = {"options": options} + obj = CreateSecgroup(args, {}) + obj.run({}) + self.assertTrue(mock_get_neutron_client.called) + self.assertTrue(mock_create_security_group_full.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_subnet.py b/tests/unit/benchmark/scenarios/lib/test_create_subnet.py new file mode 100644 index 000000000..0154755c4 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_subnet.py @@ -0,0 +1,41 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_subnet import CreateSubnet + + +class CreateSubnetTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + @mock.patch('yardstick.common.openstack_utils.create_neutron_subnet') + def test_create_subnet(self, mock_get_neutron_client, mock_create_neutron_subnet): + options = { + 'openstack_paras': { + 'network_id': '123-123-123', + 'name': 'yardstick_subnet', + 'cidr': '10.10.10.0/24', + 'ip_version': '4' + } + } + args = {"options": options} + obj = CreateSubnet(args, {}) + obj.run({}) + self.assertTrue(mock_get_neutron_client.called) + self.assertTrue(mock_create_neutron_subnet.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/benchmark/scenarios/lib/create_keypair.py b/yardstick/benchmark/scenarios/lib/create_keypair.py index 5610de651..2185bfa5d 100644 --- a/yardstick/benchmark/scenarios/lib/create_keypair.py +++ b/yardstick/benchmark/scenarios/lib/create_keypair.py @@ -57,8 +57,10 @@ class CreateKeypair(base.Scenario): self.key_filename + ".pub") if keypair: + result.update({"keypair_create": 1}) LOG.info("Create keypair successful!") else: + result.update({"keypair_create": 0}) LOG.info("Create keypair failed!") try: keys = self.scenario_cfg.get('output', '').split() diff --git a/yardstick/benchmark/scenarios/lib/create_network.py b/yardstick/benchmark/scenarios/lib/create_network.py new file mode 100644 index 000000000..cffff132a --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_network.py @@ -0,0 +1,64 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateNetwork(base.Scenario): + """Create an OpenStack network""" + + __scenario_type__ = "CreateNetwork" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.openstack = self.options.get("openstack_paras", None) + + self.neutron_client = op_utils.get_neutron_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + openstack_paras = {'network': self.openstack} + network_id = op_utils.create_neutron_net(self.neutron_client, + openstack_paras) + if network_id: + result.update({"network_create": 1}) + LOG.info("Create network successful!") + else: + result.update({"network_create": 0}) + LOG.error("Create network failed!") + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [network_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_port.py b/yardstick/benchmark/scenarios/lib/create_port.py new file mode 100644 index 000000000..6a3a23a10 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_port.py @@ -0,0 +1,66 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreatePort(base.Scenario): + """Create an OpenStack flavor""" + + __scenario_type__ = "CreatePort" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.openstack = self.options.get("openstack_paras", None) + + self.neutron_client = op_utils.get_neutron_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + openstack_paras = {'port': self.openstack} + port = self.neutron_client.create_port(openstack_paras) + + if port: + result.update({"Port_Create": 1}) + LOG.info("Create Port successful!") + else: + result.update({"Port_Create": 0}) + LOG.error("Create Port failed!") + + check_result = port['port']['id'] + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [check_result] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_router.py b/yardstick/benchmark/scenarios/lib/create_router.py new file mode 100644 index 000000000..9aa57ebb2 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_router.py @@ -0,0 +1,66 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateRouter(base.Scenario): + """Create an OpenStack router""" + + __scenario_type__ = "CreateRouter" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.openstack = self.options.get("openstack_paras", None) + + self.neutron_client = op_utils.get_neutron_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + openstack_paras = {'router': self.openstack} + router_id = op_utils.create_neutron_router(self.neutron_client, + openstack_paras) + if router_id: + result.update({"network_create": 1}) + LOG.info("Create router successful!") + else: + result.update({"network_create": 0}) + LOG.error("Create router failed!") + + check_result = router_id + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [check_result] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_sec_group.py b/yardstick/benchmark/scenarios/lib/create_sec_group.py new file mode 100644 index 000000000..3d1aec9e8 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_sec_group.py @@ -0,0 +1,65 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateSecgroup(base.Scenario): + """Create an OpenStack security group""" + + __scenario_type__ = "CreateSecgroup" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.sg_name = self.options.get("sg_name", "yardstick_sec_group") + self.description = self.options.get("description", None) + self.neutron_client = op_utils.get_neutron_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + sg_id = op_utils.create_security_group_full(self.neutron_client, + sg_name=self.sg_name, + sg_description=self.description) + + if sg_id: + result.update({"sg_create": 1}) + LOG.info("Create security group successful!") + else: + result.update({"sg_create": 0}) + LOG.error("Create security group failed!") + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [sg_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_server.py b/yardstick/benchmark/scenarios/lib/create_server.py index 45c0bfde9..273b0045a 100644 --- a/yardstick/benchmark/scenarios/lib/create_server.py +++ b/yardstick/benchmark/scenarios/lib/create_server.py @@ -59,8 +59,10 @@ class CreateServer(base.Scenario): vm = op_utils.create_instance_and_wait_for_active(self.openstack) if vm: + result.update({"instance_create": 1}) LOG.info("Create server successful!") else: + result.update({"instance_create": 0}) LOG.error("Create server failed!") try: diff --git a/yardstick/benchmark/scenarios/lib/create_subnet.py b/yardstick/benchmark/scenarios/lib/create_subnet.py new file mode 100644 index 000000000..c34af8a9e --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_subnet.py @@ -0,0 +1,66 @@ +############################################################################## +# Copyright (c) 2017 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 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateSubnet(base.Scenario): + """Create an OpenStack flavor""" + + __scenario_type__ = "CreateSubnet" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.openstack = self.options.get("openstack_paras", None) + + self.neutron_client = op_utils.get_neutron_client() + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + openstack_paras = {'subnets': [self.openstack]} + subnet_id = op_utils.create_neutron_subnet(self.neutron_client, + openstack_paras) + if subnet_id: + result.update({"subnet_create": 1}) + LOG.info("Create subnet successful!") + else: + result.update({"subnet_create": 0}) + LOG.error("Create subnet failed!") + + check_result = subnet_id + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [check_result] + return self._push_to_outputs(keys, values) diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index 540d8d641..76acc9508 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -437,6 +437,36 @@ def get_port_id_by_ip(neutron_client, ip_address): # pragma: no cover 'fixed_ips') if j['ip_address'] == ip_address), None) +def create_neutron_net(neutron_client, json_body): # pragma: no cover + try: + network = neutron_client.create_network(body=json_body) + return network['network']['id'] + except Exception: + log.error("Error [create_neutron_net(neutron_client)]") + raise Exception("operation error") + return None + + +def create_neutron_subnet(neutron_client, json_body): # pragma: no cover + try: + subnet = neutron_client.create_subnet(body=json_body) + return subnet['subnets'][0]['id'] + except Exception: + log.error("Error [create_neutron_subnet") + raise Exception("operation error") + return None + + +def create_neutron_router(neutron_client, json_body): # pragma: no cover + try: + router = neutron_client.create_router(json_body) + return router['router']['id'] + except Exception: + log.error("Error [create_neutron_router(neutron_client)]") + raise Exception("operation error") + return None + + def create_floating_ip(neutron_client, extnet_id): # pragma: no cover props = {'floating_network_id': extnet_id} try: @@ -449,6 +479,120 @@ def create_floating_ip(neutron_client, extnet_id): # pragma: no cover return {'fip_addr': fip_addr, 'fip_id': fip_id} +def get_security_groups(neutron_client): # pragma: no cover + try: + security_groups = neutron_client.list_security_groups()[ + 'security_groups'] + return security_groups + except Exception: + log.error("Error [get_security_groups(neutron_client)]") + return None + + +def get_security_group_id(neutron_client, sg_name): # pragma: no cover + security_groups = get_security_groups(neutron_client) + id = '' + for sg in security_groups: + if sg['name'] == sg_name: + id = sg['id'] + break + return id + + +def create_security_group(neutron_client, sg_name, sg_description): # pragma: no cover + json_body = {'security_group': {'name': sg_name, + 'description': sg_description}} + try: + secgroup = neutron_client.create_security_group(json_body) + return secgroup['security_group'] + except Exception: + log.error("Error [create_security_group(neutron_client, '%s', " + "'%s')]" % (sg_name, sg_description)) + return None + + +def create_secgroup_rule(neutron_client, sg_id, direction, protocol, + port_range_min=None, port_range_max=None, + **json_body): # pragma: no cover + # We create a security group in 2 steps + # 1 - we check the format and set the json body accordingly + # 2 - we call neturon client to create the security group + + # Format check + json_body.update({'security_group_rule': {'direction': direction, + 'security_group_id': sg_id, 'protocol': protocol}}) + # parameters may be + # - both None => we do nothing + # - both Not None => we add them to the json description + # but one cannot be None is the other is not None + if (port_range_min is not None and port_range_max is not None): + # add port_range in json description + json_body['security_group_rule']['port_range_min'] = port_range_min + json_body['security_group_rule']['port_range_max'] = port_range_max + log.debug("Security_group format set (port range included)") + else: + # either both port range are set to None => do nothing + # or one is set but not the other => log it and return False + if port_range_min is None and port_range_max is None: + log.debug("Security_group format set (no port range mentioned)") + else: + log.error("Bad security group format." + "One of the port range is not properly set:" + "range min: {}," + "range max: {}".format(port_range_min, + port_range_max)) + return False + + # Create security group using neutron client + try: + neutron_client.create_security_group_rule(json_body) + return True + except Exception: + log.exception("Impossible to create_security_group_rule," + "security group rule probably already exists") + return False + + +def create_security_group_full(neutron_client, + sg_name, sg_description): # pragma: no cover + sg_id = get_security_group_id(neutron_client, sg_name) + if sg_id != '': + log.info("Using existing security group '%s'..." % sg_name) + else: + log.info("Creating security group '%s'..." % sg_name) + SECGROUP = create_security_group(neutron_client, + sg_name, + sg_description) + if not SECGROUP: + log.error("Failed to create the security group...") + return None + + sg_id = SECGROUP['id'] + + log.debug("Security group '%s' with ID=%s created successfully." + % (SECGROUP['name'], sg_id)) + + log.debug("Adding ICMP rules in security group '%s'..." + % sg_name) + if not create_secgroup_rule(neutron_client, sg_id, + 'ingress', 'icmp'): + log.error("Failed to create the security group rule...") + return None + + log.debug("Adding SSH rules in security group '%s'..." + % sg_name) + if not create_secgroup_rule( + neutron_client, sg_id, 'ingress', 'tcp', '22', '22'): + log.error("Failed to create the security group rule...") + return None + + if not create_secgroup_rule( + neutron_client, sg_id, 'egress', 'tcp', '22', '22'): + log.error("Failed to create the security group rule...") + return None + return sg_id + + # ********************************************* # GLANCE # ********************************************* -- 2.16.6