[Floating IP] Neutron support for "ip floating create" command
This patch adds --subnet, --port, --floating-ip-address and --fixed-ip-address options only. Project related options will be added in another patch because it relates to identity v2 and v3, which will make the unit tests too complicated in one single patch. Change-Id: I3cce4404a114ff128b74e4596f0e847be2846b17 Partial-Bug: 1519502 Related-to: blueprint neutron-client
This commit is contained in:
parent
4b4349ee68
commit
860dbc132d
@ -33,11 +33,35 @@ Create new floating IP address
|
|||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
os ip floating create
|
os ip floating create
|
||||||
<pool>
|
[--subnet <subnet>]
|
||||||
|
[--port <port>]
|
||||||
|
[--floating-ip-address <floating-ip-address>]
|
||||||
|
[--fixed-ip-address <fixed-ip-address>]
|
||||||
|
<network>
|
||||||
|
|
||||||
.. describe:: <pool>
|
.. option:: --subnet <subnet>
|
||||||
|
|
||||||
Pool to fetch IP address from (name or ID)
|
Subnet on which you want to create the floating IP (name or ID)
|
||||||
|
(Network v2 only)
|
||||||
|
|
||||||
|
.. option:: --port <port>
|
||||||
|
|
||||||
|
Port to be associated with the floating IP (name or ID)
|
||||||
|
(Network v2 only)
|
||||||
|
|
||||||
|
.. option:: --floating-ip-address <floating-ip-address>
|
||||||
|
|
||||||
|
Floating IP address
|
||||||
|
(Network v2 only)
|
||||||
|
|
||||||
|
.. option:: --fixed-ip-address <fixed-ip-address>
|
||||||
|
|
||||||
|
Fixed IP address mapped to the floating IP
|
||||||
|
(Network v2 only)
|
||||||
|
|
||||||
|
.. describe:: <network>
|
||||||
|
|
||||||
|
Network to allocate floating IP from (name or ID)
|
||||||
|
|
||||||
ip floating delete
|
ip floating delete
|
||||||
------------------
|
------------------
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
"""Floating IP action implementations"""
|
"""Floating IP action implementations"""
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from openstackclient.common import command
|
from openstackclient.common import command
|
||||||
from openstackclient.common import utils
|
from openstackclient.common import utils
|
||||||
|
|
||||||
@ -47,27 +45,6 @@ class AddFloatingIP(command.Command):
|
|||||||
server.add_floating_ip(parsed_args.ip_address)
|
server.add_floating_ip(parsed_args.ip_address)
|
||||||
|
|
||||||
|
|
||||||
class CreateFloatingIP(command.ShowOne):
|
|
||||||
"""Create new floating IP address"""
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
|
||||||
parser = super(CreateFloatingIP, self).get_parser(prog_name)
|
|
||||||
parser.add_argument(
|
|
||||||
'pool',
|
|
||||||
metavar='<pool>',
|
|
||||||
help='Pool to fetch IP address from (name or ID)',
|
|
||||||
)
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
compute_client = self.app.client_manager.compute
|
|
||||||
floating_ip = compute_client.floating_ips.create(parsed_args.pool)
|
|
||||||
|
|
||||||
info = {}
|
|
||||||
info.update(floating_ip._info)
|
|
||||||
return zip(*sorted(six.iteritems(info)))
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveFloatingIP(command.Command):
|
class RemoveFloatingIP(command.Command):
|
||||||
"""Remove floating IP address from server"""
|
"""Remove floating IP address from server"""
|
||||||
|
|
||||||
|
@ -25,6 +25,89 @@ def _get_columns(item):
|
|||||||
return tuple(sorted(columns))
|
return tuple(sorted(columns))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_attrs(client_manager, parsed_args):
|
||||||
|
attrs = {}
|
||||||
|
network_client = client_manager.network
|
||||||
|
|
||||||
|
if parsed_args.network is not None:
|
||||||
|
network = network_client.find_network(parsed_args.network,
|
||||||
|
ignore_missing=False)
|
||||||
|
attrs['floating_network_id'] = network.id
|
||||||
|
|
||||||
|
if parsed_args.subnet is not None:
|
||||||
|
subnet = network_client.find_subnet(parsed_args.subnet,
|
||||||
|
ignore_missing=False)
|
||||||
|
attrs['subnet_id'] = subnet.id
|
||||||
|
|
||||||
|
if parsed_args.port is not None:
|
||||||
|
port = network_client.find_port(parsed_args.port,
|
||||||
|
ignore_missing=False)
|
||||||
|
attrs['port_id'] = port.id
|
||||||
|
|
||||||
|
if parsed_args.floating_ip_address is not None:
|
||||||
|
attrs['floating_ip_address'] = parsed_args.floating_ip_address
|
||||||
|
|
||||||
|
if parsed_args.fixed_ip_address is not None:
|
||||||
|
attrs['fixed_ip_address'] = parsed_args.fixed_ip_address
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
class CreateFloatingIP(common.NetworkAndComputeShowOne):
|
||||||
|
"""Create floating IP"""
|
||||||
|
|
||||||
|
def update_parser_common(self, parser):
|
||||||
|
# In Compute v2 network, floating IPs could be allocated from floating
|
||||||
|
# IP pools, which are actually external networks. So deprecate the
|
||||||
|
# parameter "pool", and use "network" instead.
|
||||||
|
parser.add_argument(
|
||||||
|
'network',
|
||||||
|
metavar='<network>',
|
||||||
|
help='Network to allocate floating IP from (name or ID)',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def update_parser_network(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--subnet',
|
||||||
|
metavar='<subnet>',
|
||||||
|
help="Subnet on which you want to create the floating IP "
|
||||||
|
"(name or ID)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--port',
|
||||||
|
metavar='<port>',
|
||||||
|
help="Port to be associated with the floating IP "
|
||||||
|
"(name or ID)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--floating-ip-address',
|
||||||
|
metavar='<floating-ip-address>',
|
||||||
|
dest='floating_ip_address',
|
||||||
|
help="Floating IP address"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--fixed-ip-address',
|
||||||
|
metavar='<fixed-ip-address>',
|
||||||
|
dest='fixed_ip_address',
|
||||||
|
help="Fixed IP address mapped to the floating IP"
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action_network(self, client, parsed_args):
|
||||||
|
attrs = _get_attrs(self.app.client_manager, parsed_args)
|
||||||
|
obj = client.create_ip(**attrs)
|
||||||
|
columns = _get_columns(obj)
|
||||||
|
data = utils.get_item_properties(obj, columns)
|
||||||
|
return (columns, data)
|
||||||
|
|
||||||
|
def take_action_compute(self, client, parsed_args):
|
||||||
|
obj = client.floating_ips.create(parsed_args.network)
|
||||||
|
columns = _get_columns(obj._info)
|
||||||
|
data = utils.get_dict_properties(obj._info, columns)
|
||||||
|
return (columns, data)
|
||||||
|
|
||||||
|
|
||||||
class DeleteFloatingIP(common.NetworkAndComputeCommand):
|
class DeleteFloatingIP(common.NetworkAndComputeCommand):
|
||||||
"""Delete floating IP"""
|
"""Delete floating IP"""
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import mock
|
|||||||
from openstackclient.network.v2 import floating_ip
|
from openstackclient.network.v2 import floating_ip
|
||||||
from openstackclient.tests.compute.v2 import fakes as compute_fakes
|
from openstackclient.tests.compute.v2 import fakes as compute_fakes
|
||||||
from openstackclient.tests.network.v2 import fakes as network_fakes
|
from openstackclient.tests.network.v2 import fakes as network_fakes
|
||||||
|
from openstackclient.tests import utils as tests_utils
|
||||||
|
|
||||||
|
|
||||||
# Tests for Neutron network
|
# Tests for Neutron network
|
||||||
@ -29,6 +30,115 @@ class TestFloatingIPNetwork(network_fakes.TestNetworkV2):
|
|||||||
self.network = self.app.client_manager.network
|
self.network = self.app.client_manager.network
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateFloatingIPNetwork(TestFloatingIPNetwork):
|
||||||
|
|
||||||
|
# Fake data for option tests.
|
||||||
|
floating_network = network_fakes.FakeNetwork.create_one_network()
|
||||||
|
subnet = network_fakes.FakeSubnet.create_one_subnet()
|
||||||
|
port = network_fakes.FakePort.create_one_port()
|
||||||
|
|
||||||
|
# The floating ip to be deleted.
|
||||||
|
floating_ip = network_fakes.FakeFloatingIP.create_one_floating_ip(
|
||||||
|
attrs={
|
||||||
|
'floating_network_id': floating_network.id,
|
||||||
|
'port_id': port.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
columns = (
|
||||||
|
'dns_domain',
|
||||||
|
'dns_name',
|
||||||
|
'fixed_ip_address',
|
||||||
|
'floating_ip_address',
|
||||||
|
'floating_network_id',
|
||||||
|
'id',
|
||||||
|
'port_id',
|
||||||
|
'project_id',
|
||||||
|
'router_id',
|
||||||
|
'status',
|
||||||
|
)
|
||||||
|
|
||||||
|
data = (
|
||||||
|
floating_ip.dns_domain,
|
||||||
|
floating_ip.dns_name,
|
||||||
|
floating_ip.fixed_ip_address,
|
||||||
|
floating_ip.floating_ip_address,
|
||||||
|
floating_ip.floating_network_id,
|
||||||
|
floating_ip.id,
|
||||||
|
floating_ip.port_id,
|
||||||
|
floating_ip.project_id,
|
||||||
|
floating_ip.router_id,
|
||||||
|
floating_ip.status,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestCreateFloatingIPNetwork, self).setUp()
|
||||||
|
|
||||||
|
self.network.create_ip = mock.Mock(return_value=self.floating_ip)
|
||||||
|
|
||||||
|
self.network.find_network = mock.Mock(
|
||||||
|
return_value=self.floating_network)
|
||||||
|
self.network.find_subnet = mock.Mock(return_value=self.subnet)
|
||||||
|
self.network.find_port = mock.Mock(return_value=self.port)
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = floating_ip.CreateFloatingIP(self.app, self.namespace)
|
||||||
|
|
||||||
|
def test_create_no_options(self):
|
||||||
|
arglist = []
|
||||||
|
verifylist = []
|
||||||
|
|
||||||
|
# Missing required args should bail here
|
||||||
|
self.assertRaises(tests_utils.ParserException, self.check_parser,
|
||||||
|
self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
def test_create_default_options(self):
|
||||||
|
arglist = [
|
||||||
|
self.floating_ip.floating_network_id,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('network', self.floating_ip.floating_network_id),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.network.create_ip.assert_called_once_with(**{
|
||||||
|
'floating_network_id': self.floating_ip.floating_network_id,
|
||||||
|
})
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
def test_create_all_options(self):
|
||||||
|
arglist = [
|
||||||
|
'--subnet', self.subnet.id,
|
||||||
|
'--port', self.floating_ip.port_id,
|
||||||
|
'--floating-ip-address', self.floating_ip.floating_ip_address,
|
||||||
|
'--fixed-ip-address', self.floating_ip.fixed_ip_address,
|
||||||
|
self.floating_ip.floating_network_id,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('subnet', self.subnet.id),
|
||||||
|
('port', self.floating_ip.port_id),
|
||||||
|
('floating_ip_address', self.floating_ip.floating_ip_address),
|
||||||
|
('fixed_ip_address', self.floating_ip.fixed_ip_address),
|
||||||
|
('network', self.floating_ip.floating_network_id),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.network.create_ip.assert_called_once_with(**{
|
||||||
|
'subnet_id': self.subnet.id,
|
||||||
|
'port_id': self.floating_ip.port_id,
|
||||||
|
'floating_ip_address': self.floating_ip.floating_ip_address,
|
||||||
|
'fixed_ip_address': self.floating_ip.fixed_ip_address,
|
||||||
|
'floating_network_id': self.floating_ip.floating_network_id,
|
||||||
|
})
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork):
|
class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork):
|
||||||
|
|
||||||
# The floating ip to be deleted.
|
# The floating ip to be deleted.
|
||||||
@ -169,6 +279,62 @@ class TestFloatingIPCompute(compute_fakes.TestComputev2):
|
|||||||
self.compute = self.app.client_manager.compute
|
self.compute = self.app.client_manager.compute
|
||||||
|
|
||||||
|
|
||||||
|
class TestCreateFloatingIPCompute(TestFloatingIPCompute):
|
||||||
|
|
||||||
|
# The floating ip to be deleted.
|
||||||
|
floating_ip = compute_fakes.FakeFloatingIP.create_one_floating_ip()
|
||||||
|
|
||||||
|
columns = (
|
||||||
|
'fixed_ip',
|
||||||
|
'id',
|
||||||
|
'instance_id',
|
||||||
|
'ip',
|
||||||
|
'pool',
|
||||||
|
)
|
||||||
|
|
||||||
|
data = (
|
||||||
|
floating_ip.fixed_ip,
|
||||||
|
floating_ip.id,
|
||||||
|
floating_ip.instance_id,
|
||||||
|
floating_ip.ip,
|
||||||
|
floating_ip.pool,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestCreateFloatingIPCompute, self).setUp()
|
||||||
|
|
||||||
|
self.app.client_manager.network_endpoint_enabled = False
|
||||||
|
|
||||||
|
self.compute.floating_ips.create.return_value = self.floating_ip
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = floating_ip.CreateFloatingIP(self.app, None)
|
||||||
|
|
||||||
|
def test_create_no_options(self):
|
||||||
|
arglist = []
|
||||||
|
verifylist = []
|
||||||
|
|
||||||
|
# Missing required args should bail here
|
||||||
|
self.assertRaises(tests_utils.ParserException, self.check_parser,
|
||||||
|
self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
def test_create_default_options(self):
|
||||||
|
arglist = [
|
||||||
|
self.floating_ip.pool,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('network', self.floating_ip.pool),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.compute.floating_ips.create.assert_called_once_with(
|
||||||
|
self.floating_ip.pool)
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.data, data)
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteFloatingIPCompute(TestFloatingIPCompute):
|
class TestDeleteFloatingIPCompute(TestFloatingIPCompute):
|
||||||
|
|
||||||
# The floating ip to be deleted.
|
# The floating ip to be deleted.
|
||||||
|
4
releasenotes/notes/bug-1519502-d534db6c18adef20.yaml
Normal file
4
releasenotes/notes/bug-1519502-d534db6c18adef20.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Command ``ip floating create`` is now available for neutron network.
|
||||||
|
[Bug `1519502 <https://bugs.launchpad.net/python-openstackclient/+bug/1519502>`_]
|
@ -91,7 +91,6 @@ openstack.compute.v2 =
|
|||||||
ip_fixed_remove = openstackclient.compute.v2.fixedip:RemoveFixedIP
|
ip_fixed_remove = openstackclient.compute.v2.fixedip:RemoveFixedIP
|
||||||
|
|
||||||
ip_floating_add = openstackclient.compute.v2.floatingip:AddFloatingIP
|
ip_floating_add = openstackclient.compute.v2.floatingip:AddFloatingIP
|
||||||
ip_floating_create = openstackclient.compute.v2.floatingip:CreateFloatingIP
|
|
||||||
ip_floating_remove = openstackclient.compute.v2.floatingip:RemoveFloatingIP
|
ip_floating_remove = openstackclient.compute.v2.floatingip:RemoveFloatingIP
|
||||||
ip_floating_pool_list = openstackclient.compute.v2.floatingippool:ListFloatingIPPool
|
ip_floating_pool_list = openstackclient.compute.v2.floatingippool:ListFloatingIPPool
|
||||||
|
|
||||||
@ -322,6 +321,7 @@ openstack.image.v2 =
|
|||||||
image_set = openstackclient.image.v2.image:SetImage
|
image_set = openstackclient.image.v2.image:SetImage
|
||||||
|
|
||||||
openstack.network.v2 =
|
openstack.network.v2 =
|
||||||
|
ip_floating_create = openstackclient.network.v2.floating_ip:CreateFloatingIP
|
||||||
ip_floating_delete = openstackclient.network.v2.floating_ip:DeleteFloatingIP
|
ip_floating_delete = openstackclient.network.v2.floating_ip:DeleteFloatingIP
|
||||||
ip_floating_list = openstackclient.network.v2.floating_ip:ListFloatingIP
|
ip_floating_list = openstackclient.network.v2.floating_ip:ListFloatingIP
|
||||||
ip_floating_show = openstackclient.network.v2.floating_ip:ShowFloatingIP
|
ip_floating_show = openstackclient.network.v2.floating_ip:ShowFloatingIP
|
||||||
|
Loading…
Reference in New Issue
Block a user