diff --git a/doc/source/command-objects/ip-floating.rst b/doc/source/command-objects/ip-floating.rst index 6bfd7f4498..efdfb45313 100644 --- a/doc/source/command-objects/ip-floating.rst +++ b/doc/source/command-objects/ip-floating.rst @@ -2,7 +2,7 @@ ip floating =========== -Compute v2 +Compute v2, Network v2 ip floating add --------------- @@ -42,17 +42,16 @@ Create new floating IP address ip floating delete ------------------ -Delete a floating IP address +Delete floating IP .. program:: ip floating delete -.. code:: bash + .. code:: bash - os ip floating delete - + os ip floating delete -.. describe:: +.. describe:: - IP address to delete (ID only) + Floating IP to delete (IP address or ID) ip floating list ---------------- diff --git a/openstackclient/compute/v2/floatingip.py b/openstackclient/compute/v2/floatingip.py index 29ecbc9057..e4280de745 100644 --- a/openstackclient/compute/v2/floatingip.py +++ b/openstackclient/compute/v2/floatingip.py @@ -68,29 +68,6 @@ class CreateFloatingIP(command.ShowOne): return zip(*sorted(six.iteritems(info))) -class DeleteFloatingIP(command.Command): - """Delete a floating IP address""" - - def get_parser(self, prog_name): - parser = super(DeleteFloatingIP, self).get_parser(prog_name) - parser.add_argument( - "ip_address", - metavar="", - help="IP address to delete (ID only)", - ) - return parser - - def take_action(self, parsed_args): - compute_client = self.app.client_manager.compute - - floating_ip = utils.find_resource( - compute_client.floating_ips, - parsed_args.ip_address, - ) - - compute_client.floating_ips.delete(floating_ip) - - class ListFloatingIP(command.Lister): """List floating IP addresses""" diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py new file mode 100644 index 0000000000..91a93380a9 --- /dev/null +++ b/openstackclient/network/v2/floating_ip.py @@ -0,0 +1,40 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""IP Floating action implementations""" + +from openstackclient.common import utils +from openstackclient.network import common + + +class DeleteFloatingIP(common.NetworkAndComputeCommand): + """Delete floating IP""" + + def update_parser_common(self, parser): + parser.add_argument( + 'floating_ip', + metavar="", + help=("Floating IP to delete (IP address or ID)") + ) + return parser + + def take_action_network(self, client, parsed_args): + obj = client.find_ip(parsed_args.floating_ip) + client.delete_ip(obj) + + def take_action_compute(self, client, parsed_args): + obj = utils.find_resource( + client.floating_ips, + parsed_args.floating_ip, + ) + client.floating_ips.delete(obj.id) diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index 68a66740ca..2e4cc1c56b 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -126,6 +126,9 @@ class FakeComputev2Client(object): self.security_group_rules = mock.Mock() self.security_group_rules.resource_class = fakes.FakeResource(None, {}) + self.floating_ips = mock.Mock() + self.floating_ips.resource_class = fakes.FakeResource(None, {}) + self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py index 516995eb02..7dee41e00e 100644 --- a/openstackclient/tests/network/v2/fakes.py +++ b/openstackclient/tests/network/v2/fakes.py @@ -226,7 +226,6 @@ class FakePort(object): :return: A FakeResource object, with id, name, etc. """ - # Set default attributes. port_attrs = { 'admin_state_up': True, @@ -553,3 +552,79 @@ class FakeSubnet(object): subnets.append(FakeSubnet.create_one_subnet(attrs, methods)) return subnets + + +class FakeFloatingIP(object): + """Fake one or more floating ip.""" + + @staticmethod + def create_one_floating_ip(attrs={}, methods={}): + """Create a fake floating ip. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object, with id, ip + """ + # Set default attributes. + floating_ip_attrs = { + 'id': 'floating-ip-id-' + uuid.uuid4().hex, + 'ip': '1.0.9.0', + } + + # Overwrite default attributes. + floating_ip_attrs.update(attrs) + + # Set default methods. + floating_ip_methods = {} + + # Overwrite default methods. + floating_ip_methods.update(methods) + + floating_ip = fakes.FakeResource( + info=copy.deepcopy(floating_ip_attrs), + methods=copy.deepcopy(floating_ip_methods), + loaded=True) + return floating_ip + + @staticmethod + def create_floating_ips(attrs={}, methods={}, count=2): + """Create multiple fake floating ips. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of floating ips to fake + :return: + A list of FakeResource objects faking the floating ips + """ + floating_ips = [] + for i in range(0, count): + floating_ips.append(FakeFloatingIP.create_one_floating_ip( + attrs, + methods + )) + return floating_ips + + @staticmethod + def get_floating_ips(floating_ips=None, count=2): + """Get an iterable MagicMock object with a list of faked floating ips. + + If floating_ips list is provided, then initialize the Mock object + with the list. Otherwise create one. + + :param List floating ips: + A list of FakeResource objects faking floating ips + :param int count: + The number of floating ips to fake + :return: + An iterable Mock object with side_effect set to a list of faked + floating ips + """ + if floating_ips is None: + floating_ips = FakeFloatingIP.create_floating_ips(count) + return mock.MagicMock(side_effect=floating_ips) diff --git a/openstackclient/tests/network/v2/test_floating_ip.py b/openstackclient/tests/network/v2/test_floating_ip.py new file mode 100644 index 0000000000..49131f364c --- /dev/null +++ b/openstackclient/tests/network/v2/test_floating_ip.py @@ -0,0 +1,105 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.network.v2 import floating_ip +from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests.network.v2 import fakes as network_fakes + + +# Tests for Neutron network +# +class TestFloatingIPNetwork(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestFloatingIPNetwork, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork): + + # The floating ip to be deleted. + floating_ip = network_fakes.FakeFloatingIP.create_one_floating_ip() + + def setUp(self): + super(TestDeleteFloatingIPNetwork, self).setUp() + + self.network.delete_ip = mock.Mock(return_value=self.floating_ip) + self.network.find_ip = mock.Mock(return_value=self.floating_ip) + + # Get the command object to test + self.cmd = floating_ip.DeleteFloatingIP(self.app, self.namespace) + + def test_floating_ip_delete(self): + arglist = [ + self.floating_ip.id, + ] + verifylist = [ + ('floating_ip', self.floating_ip.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.network.find_ip.assert_called_with(self.floating_ip.id) + self.network.delete_ip.assert_called_with(self.floating_ip) + self.assertIsNone(result) + + +# Tests for Nova network +# +class TestFloatingIPCompute(compute_fakes.TestComputev2): + + def setUp(self): + super(TestFloatingIPCompute, self).setUp() + + # Get a shortcut to the compute client + self.compute = self.app.client_manager.compute + + +class TestDeleteFloatingIPCompute(TestFloatingIPCompute): + + # The floating ip to be deleted. + floating_ip = network_fakes.FakeFloatingIP.create_one_floating_ip() + + def setUp(self): + super(TestDeleteFloatingIPCompute, self).setUp() + + self.app.client_manager.network_endpoint_enabled = False + + self.compute.floating_ips.delete.return_value = None + + # Return value of utils.find_resource() + self.compute.floating_ips.get.return_value = self.floating_ip + + # Get the command object to test + self.cmd = floating_ip.DeleteFloatingIP(self.app, None) + + def test_floating_ip_delete(self): + arglist = [ + self.floating_ip.id, + ] + verifylist = [ + ('floating_ip', self.floating_ip.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.compute.floating_ips.delete.assert_called_with( + self.floating_ip.id + ) + self.assertIsNone(result) diff --git a/setup.cfg b/setup.cfg index 4cf9622ceb..dabe779c3c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -91,10 +91,8 @@ openstack.compute.v2 = ip_floating_add = openstackclient.compute.v2.floatingip:AddFloatingIP ip_floating_create = openstackclient.compute.v2.floatingip:CreateFloatingIP - ip_floating_delete = openstackclient.compute.v2.floatingip:DeleteFloatingIP ip_floating_list = openstackclient.compute.v2.floatingip:ListFloatingIP ip_floating_remove = openstackclient.compute.v2.floatingip:RemoveFloatingIP - ip_floating_pool_list = openstackclient.compute.v2.floatingippool:ListFloatingIPPool keypair_create = openstackclient.compute.v2.keypair:CreateKeypair @@ -327,6 +325,7 @@ openstack.image.v2 = image_set = openstackclient.image.v2.image:SetImage openstack.network.v2 = + ip_floating_delete = openstackclient.network.v2.floating_ip:DeleteFloatingIP network_create = openstackclient.network.v2.network:CreateNetwork network_delete = openstackclient.network.v2.network:DeleteNetwork network_list = openstackclient.network.v2.network:ListNetwork