From ab03bfeafda0a29def4c792a174ec1af836b68be Mon Sep 17 00:00:00 2001 From: Andrey Kurilin Date: Tue, 4 Aug 2020 13:48:26 +0300 Subject: [PATCH] Fix nova scenarios for assiciating fips Two scenarios were not properly adopted while switching from network wrapper usage Change-Id: I677d45d11614acf48b979db1c64fc115cedd612e --- .../task/scenarios/nova/servers.py | 57 ++++++++--- .../nova/boot-and-associate-floating-ip.json | 4 +- .../nova/boot-and-associate-floating-ip.yaml | 3 +- ...-associate-and-dissociate-floating-ip.json | 4 +- ...-associate-and-dissociate-floating-ip.yaml | 3 +- tests/ci/cover.sh | 2 +- .../unit/task/scenarios/nova/test_servers.py | 98 +++++++++++++++++++ 7 files changed, 146 insertions(+), 25 deletions(-) diff --git a/rally_openstack/task/scenarios/nova/servers.py b/rally_openstack/task/scenarios/nova/servers.py index c3938954..11dc2f15 100644 --- a/rally_openstack/task/scenarios/nova/servers.py +++ b/rally_openstack/task/scenarios/nova/servers.py @@ -901,31 +901,46 @@ class BootAndRebuildServer(utils.NovaScenario): self._delete_server(server) +@logging.log_deprecated_args( + "Use 'floating_network' for additional instance parameters.", + "2.1.0", ["create_floating_ip_args"], once=True) @types.convert(image={"type": "glance_image"}, flavor={"type": "nova_flavor"}) @validation.add("image_valid_on_flavor", flavor_param="flavor", image_param="image") @validation.add("required_services", services=[consts.Service.NOVA]) @validation.add("required_platform", platform="openstack", users=True) -@validation.add("required_contexts", contexts=("network")) +@validation.add("required_contexts", contexts=["network"]) @scenario.configure( context={"cleanup@openstack": ["nova", "neutron.floatingip"]}, name="NovaServers.boot_and_associate_floating_ip", platform="openstack") class BootAndAssociateFloatingIp(utils.NovaScenario): - def run(self, image, flavor, create_floating_ip_args=None, **kwargs): + def run(self, image, flavor, floating_network=None, + create_floating_ip_args=None, **kwargs): """Boot a server and associate a floating IP to it. :param image: image to be used to boot an instance :param flavor: flavor to be used to boot an instance - :param create_floating_ip_args: Optional additional arguments for - floating ip creation + :param floating_network: external network associated with floating IP. + :param create_floating_ip_args: Optional additional dict for specifying + external network associated with floating IP ('ext_network' key). :param kwargs: Optional additional arguments for server creation """ - create_floating_ip_args = create_floating_ip_args or {} + if floating_network is None and create_floating_ip_args: + if "ext_network" in create_floating_ip_args: + # the old way (network wrapper) + floating_network = create_floating_ip_args["ext_network"] + elif "floating_network" in create_floating_ip_args: + # the semi-old way - the time when network wrapper was replaced + # by network service, but this compatibility layer was not + # provided + floating_network = create_floating_ip_args["floating_network"] server = self._boot_server(image, flavor, **kwargs) - floatingip = self.neutron.create_floatingip(**create_floating_ip_args) + floatingip = self.neutron.create_floatingip( + floating_network=floating_network + ) self._associate_floating_ip(server, floatingip) @@ -1083,20 +1098,24 @@ class BootServerFromVolumeSnapshot(utils.NovaScenario, **kwargs) +@logging.log_deprecated_args( + "Use 'floating_network' for additional instance parameters.", + "2.1.0", ["create_floating_ip_args"], once=True) @types.convert(image={"type": "glance_image"}, flavor={"type": "nova_flavor"}) @validation.add("image_valid_on_flavor", flavor_param="flavor", image_param="image") @validation.add("required_services", services=[consts.Service.NOVA]) @validation.add("required_platform", platform="openstack", users=True) -@validation.add("required_contexts", contexts=("network")) +@validation.add("required_contexts", contexts=["network"]) @scenario.configure( context={"cleanup@openstack": ["nova", "neutron.floatingip"]}, name="NovaServers.boot_server_associate_and_dissociate_floating_ip", platform="openstack") class BootServerAssociateAndDissociateFloatingIP(utils.NovaScenario): - def run(self, image, flavor, create_floating_ip_args=None, **kwargs): + def run(self, image, flavor, floating_network=None, + create_floating_ip_args=None, **kwargs): """Boot a server associate and dissociate a floating IP from it. The scenario first boot a server and create a floating IP. then @@ -1105,14 +1124,24 @@ class BootServerAssociateAndDissociateFloatingIP(utils.NovaScenario): :param image: image to be used to boot an instance :param flavor: flavor to be used to boot an instance - :param create_floating_ip_args: Optional additional arguments for - floating ip creation + :param floating_network: external network associated with floating IP. + :param create_floating_ip_args: Optional additional dict for specifying + external network associated with floating IP ('ext_network' key). :param kwargs: Optional additional arguments for server creation """ - - create_floating_ip_args = create_floating_ip_args or {} + if floating_network is None and create_floating_ip_args: + if "ext_network" in create_floating_ip_args: + # the old way (network wrapper) + floating_network = create_floating_ip_args["ext_network"] + elif "floating_network" in create_floating_ip_args: + # the semi-old way - the time when network wrapper was replaced + # by network service, but this compatibility layer was not + # provided + floating_network = create_floating_ip_args["floating_network"] server = self._boot_server(image, flavor, **kwargs) - floatingip = self.neutron.create_floatingip(**create_floating_ip_args) + floatingip = self.neutron.create_floatingip( + floating_network=floating_network + ) self._associate_floating_ip(server, floatingip) self._dissociate_floating_ip(server, floatingip) @@ -1123,7 +1152,7 @@ class BootServerAssociateAndDissociateFloatingIP(utils.NovaScenario): image_param="image") @validation.add("required_services", services=[consts.Service.NOVA]) @validation.add("required_platform", platform="openstack", users=True) -@validation.add("required_contexts", contexts=("network")) +@validation.add("required_contexts", contexts=["network"]) @scenario.configure(context={"cleanup@openstack": ["nova"]}, name="NovaServers.boot_server_and_list_interfaces", platform="openstack") diff --git a/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.json b/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.json index b1e2c709..e73338c4 100644 --- a/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.json +++ b/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.json @@ -41,9 +41,7 @@ "image": { "name": "^cirros.*-disk$" }, - "create_floating_ip_args": { - "ext_network": "ext_network_name" - } + "floating_network": "ext_network_name" }, "context": { "users": { diff --git a/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.yaml b/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.yaml index deb5e160..bfe7aa54 100644 --- a/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.yaml +++ b/samples/tasks/scenarios/nova/boot-and-associate-floating-ip.yaml @@ -25,8 +25,7 @@ name: "{{flavor_name}}" image: name: "^cirros.*-disk$" - create_floating_ip_args: - ext_network: "ext_network_name" + floating_network: "ext_network_name" runner: type: "constant" times: 1 diff --git a/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.json b/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.json index 670bebd7..17cc526e 100644 --- a/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.json +++ b/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.json @@ -41,9 +41,7 @@ "image": { "name": "^cirros.*-disk$" }, - "create_floating_ip_args": { - "ext_network": "ext_network_name" - } + "floating_network": "ext_network_name" }, "context": { "users": { diff --git a/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.yaml b/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.yaml index a89c98fe..4aaae27e 100644 --- a/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.yaml +++ b/samples/tasks/scenarios/nova/boot-server-associate-and-dissociate-floating-ip.yaml @@ -25,8 +25,7 @@ name: "{{flavor_name}}" image: name: "^cirros.*-disk$" - create_floating_ip_args: - ext_network: "ext_network_name" + floating_network: "ext_network_name" runner: type: "constant" times: 5 diff --git a/tests/ci/cover.sh b/tests/ci/cover.sh index 11096805..7ad96b8b 100755 --- a/tests/ci/cover.sh +++ b/tests/ci/cover.sh @@ -15,7 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -ALLOWED_EXTRA_MISSING=10 +ALLOWED_EXTRA_MISSING=4 show_diff () { head -1 $1 diff --git a/tests/unit/task/scenarios/nova/test_servers.py b/tests/unit/task/scenarios/nova/test_servers.py index cd26b4e1..49cd2e02 100644 --- a/tests/unit/task/scenarios/nova/test_servers.py +++ b/tests/unit/task/scenarios/nova/test_servers.py @@ -944,6 +944,55 @@ class NovaServersTestCase(test.ScenarioTestCase): scenario._associate_floating_ip.assert_called_once_with( server, floatingip) + # check ext_network + neutronclient.list_networks.return_value = { + "networks": [ + {"id": "id1", "name": "net1", "router:external": True}, + {"id": "id2", "name": "net2", "router:external": True}, + {"id": "id3", "name": "net3", "router:external": True}, + ] + } + neutronclient.create_floatingip.reset_mock() + + # case 1: new argument is used + scenario.run(image, flavor, floating_network="net3") + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 2: new argument is transmitted with an old one + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, floating_network="net3", + create_floating_ip_args={"ext_network": "net2"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 3: new argument is transmitted with an semi-old one + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, floating_network="net3", + create_floating_ip_args={"floating_network": "net1"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 4: only old argument is transmitted + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, + create_floating_ip_args={"ext_network": "net2"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id2"}} + ) + # case 5: only semi-old argument is transmitted + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, + create_floating_ip_args={"floating_network": "net1"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id1"}} + ) + def test_boot_server_associate_and_dissociate_floating_ip(self): clients = mock.MagicMock() neutronclient = clients.neutron.return_value @@ -972,6 +1021,55 @@ class NovaServersTestCase(test.ScenarioTestCase): scenario._dissociate_floating_ip.assert_called_once_with( server, floatingip) + # check ext_network + neutronclient.list_networks.return_value = { + "networks": [ + {"id": "id1", "name": "net1", "router:external": True}, + {"id": "id2", "name": "net2", "router:external": True}, + {"id": "id3", "name": "net3", "router:external": True}, + ] + } + neutronclient.create_floatingip.reset_mock() + + # case 1: new argument is used + scenario.run(image, flavor, floating_network="net3") + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 2: new argument is transmitted with an old one + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, floating_network="net3", + create_floating_ip_args={"ext_network": "net2"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 3: new argument is transmitted with an semi-old one + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, floating_network="net3", + create_floating_ip_args={"floating_network": "net1"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id3"}} + ) + # case 4: only old argument is transmitted + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, + create_floating_ip_args={"ext_network": "net2"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id2"}} + ) + # case 5: only semi-old argument is transmitted + neutronclient.create_floatingip.reset_mock() + scenario.run(image, flavor, + create_floating_ip_args={"floating_network": "net1"}) + neutronclient.create_floatingip.assert_called_once_with( + {"floatingip": {"description": mock.ANY, + "floating_network_id": "id1"}} + ) + def test_boot_and_update_server(self): scenario = servers.BootAndUpdateServer(self.context) scenario._boot_server = mock.Mock()