Add --address-scope option "subnet pool create/set"

This patch adds --address-scope option to "subnet pool create/set"
commands, and --no-address-scope option to "subnet pool set"
command to clear the address scope setting.

Change-Id: Ie2c370a50b52574fa6ec268083ad013b7544361e
Partial-Bug: #1544586
Partial-Bug: #1544591
This commit is contained in:
Tang Chen 2016-03-24 19:22:07 +08:00
parent 6c73946623
commit b3649a54cd
4 changed files with 176 additions and 8 deletions

View File

@ -18,6 +18,7 @@ Create subnet pool
[--min-prefix-length <min-prefix-length>] [--min-prefix-length <min-prefix-length>]
[--max-prefix-length <max-prefix-length>] [--max-prefix-length <max-prefix-length>]
[--project <project> [--project-domain <project-domain>]] [--project <project> [--project-domain <project-domain>]]
[--address-scope <address-scope>]
<name> <name>
.. option:: --pool-prefix <pool-prefix> .. option:: --pool-prefix <pool-prefix>
@ -46,6 +47,11 @@ Create subnet pool
Domain the project belongs to (name or ID). This can be used in case Domain the project belongs to (name or ID). This can be used in case
collisions between project names exist. collisions between project names exist.
.. option:: --address-scope <address-scope>
Set address scope associated with the subnet pool (name or ID).
Prefixes must be unique across address scopes.
.. _subnet_pool_create-name: .. _subnet_pool_create-name:
.. describe:: <name> .. describe:: <name>
@ -96,6 +102,7 @@ Set subnet pool properties
[--default-prefix-length <default-prefix-length>] [--default-prefix-length <default-prefix-length>]
[--min-prefix-length <min-prefix-length>] [--min-prefix-length <min-prefix-length>]
[--max-prefix-length <max-prefix-length>] [--max-prefix-length <max-prefix-length>]
[--address-scope <address-scope> | --no-address-scope]
<subnet-pool> <subnet-pool>
.. option:: --name <name> .. option:: --name <name>
@ -119,6 +126,15 @@ Set subnet pool properties
Set subnet pool maximum prefix length Set subnet pool maximum prefix length
.. option:: --address-scope <address-scope>
Set address scope associated with the subnet pool (name or ID).
Prefixes must be unique across address scopes.
.. option:: --no-address-scope
Remove address scope associated with the subnet pool
.. _subnet_pool_set-subnet-pool: .. _subnet_pool_set-subnet-pool:
.. describe:: <subnet-pool> .. describe:: <subnet-pool>

View File

@ -35,6 +35,8 @@ _formatters = {
def _get_attrs(client_manager, parsed_args): def _get_attrs(client_manager, parsed_args):
attrs = {} attrs = {}
network_client = client_manager.network
if parsed_args.name is not None: if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name) attrs['name'] = str(parsed_args.name)
if parsed_args.prefixes is not None: if parsed_args.prefixes is not None:
@ -46,6 +48,12 @@ def _get_attrs(client_manager, parsed_args):
if parsed_args.max_prefix_length is not None: if parsed_args.max_prefix_length is not None:
attrs['max_prefixlen'] = parsed_args.max_prefix_length attrs['max_prefixlen'] = parsed_args.max_prefix_length
if parsed_args.address_scope is not None:
attrs['address_scope_id'] = network_client.find_address_scope(
parsed_args.address_scope, ignore_missing=False).id
if 'no_address_scope' in parsed_args and parsed_args.no_address_scope:
attrs['address_scope_id'] = None
# "subnet pool set" command doesn't support setting project. # "subnet pool set" command doesn't support setting project.
if 'project' in parsed_args and parsed_args.project is not None: if 'project' in parsed_args and parsed_args.project is not None:
identity_client = client_manager.identity identity_client = client_manager.identity
@ -105,7 +113,13 @@ class CreateSubnetPool(command.ShowOne):
help="Owner's project (name or ID)", help="Owner's project (name or ID)",
) )
identity_common.add_project_domain_option_to_parser(parser) identity_common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--address-scope',
metavar='<address-scope>',
help="Set address scope associated with the subnet pool "
"(name or ID). Prefixes must be unique across address "
"scopes.",
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -204,7 +218,19 @@ class SetSubnetPool(command.Command):
help='Set subnet pool name', help='Set subnet pool name',
) )
_add_prefix_options(parser) _add_prefix_options(parser)
address_scope_group = parser.add_mutually_exclusive_group()
address_scope_group.add_argument(
'--address-scope',
metavar='<address-scope>',
help="Set address scope associated with the subnet pool "
"(name or ID). Prefixes must be unique across address "
"scopes.",
)
address_scope_group.add_argument(
'--no-address-scope',
action='store_true',
help="Remove address scope associated with the subnet pool",
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):

View File

@ -71,6 +71,43 @@ class TestNetworkV2(utils.TestCommand):
) )
class FakeAddressScope(object):
"""Fake one or more address scopes."""
@staticmethod
def create_one_address_scope(attrs=None):
"""Create a fake address scope.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeResource object with name, id, etc.
"""
if attrs is None:
attrs = {}
# Set default attributes.
address_scope_attrs = {
'name': 'address-scope-name-' + uuid.uuid4().hex,
'id': 'address-scope-id-' + uuid.uuid4().hex,
'tenant_id': 'project-id-' + uuid.uuid4().hex,
'shared': False,
'ip_version': 4,
}
# Overwrite default attributes.
address_scope_attrs.update(attrs)
address_scope = fakes.FakeResource(
info=copy.deepcopy(address_scope_attrs),
loaded=True)
# Set attributes with special mapping in OpenStack SDK.
address_scope.project_id = address_scope_attrs['tenant_id']
return address_scope
class FakeAvailabilityZone(object): class FakeAvailabilityZone(object):
"""Fake one or more network availability zones (AZs).""" """Fake one or more network availability zones (AZs)."""

View File

@ -38,6 +38,8 @@ class TestCreateSubnetPool(TestSubnetPool):
# The new subnet pool to create. # The new subnet pool to create.
_subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool() _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
_address_scope = network_fakes.FakeAddressScope.create_one_address_scope()
columns = ( columns = (
'address_scope_id', 'address_scope_id',
'default_prefixlen', 'default_prefixlen',
@ -76,6 +78,9 @@ class TestCreateSubnetPool(TestSubnetPool):
# Get the command object to test # Get the command object to test
self.cmd = subnet_pool.CreateSubnetPool(self.app, self.namespace) self.cmd = subnet_pool.CreateSubnetPool(self.app, self.namespace)
self.network.find_address_scope = mock.Mock(
return_value=self._address_scope)
# Set identity client. And get a shortcut to Identity client. # Set identity client. And get a shortcut to Identity client.
identity_client = identity_fakes_v3.FakeIdentityv3Client( identity_client = identity_fakes_v3.FakeIdentityv3Client(
endpoint=fakes.AUTH_URL, endpoint=fakes.AUTH_URL,
@ -193,6 +198,29 @@ class TestCreateSubnetPool(TestSubnetPool):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data) self.assertEqual(self.data, data)
def test_create_address_scope_option(self):
arglist = [
'--pool-prefix', '10.0.10.0/24',
'--address-scope', self._address_scope.id,
self._subnet_pool.name,
]
verifylist = [
('prefixes', ['10.0.10.0/24']),
('address_scope', self._address_scope.id),
('name', self._subnet_pool.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_subnet_pool.assert_called_once_with(**{
'prefixes': ['10.0.10.0/24'],
'address_scope_id': self._address_scope.id,
'name': self._subnet_pool.name,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
class TestDeleteSubnetPool(TestSubnetPool): class TestDeleteSubnetPool(TestSubnetPool):
@ -301,6 +329,8 @@ class TestSetSubnetPool(TestSubnetPool):
# The subnet_pool to set. # The subnet_pool to set.
_subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool() _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
_address_scope = network_fakes.FakeAddressScope.create_one_address_scope()
def setUp(self): def setUp(self):
super(TestSetSubnetPool, self).setUp() super(TestSetSubnetPool, self).setUp()
@ -309,21 +339,24 @@ class TestSetSubnetPool(TestSubnetPool):
self.network.find_subnet_pool = mock.Mock( self.network.find_subnet_pool = mock.Mock(
return_value=self._subnet_pool) return_value=self._subnet_pool)
self.network.find_address_scope = mock.Mock(
return_value=self._address_scope)
# Get the command object to test # Get the command object to test
self.cmd = subnet_pool.SetSubnetPool(self.app, self.namespace) self.cmd = subnet_pool.SetSubnetPool(self.app, self.namespace)
def test_set_this(self): def test_set_this(self):
arglist = [ arglist = [
self._subnet_pool.name,
'--name', 'noob', '--name', 'noob',
'--default-prefix-length', '8', '--default-prefix-length', '8',
'--min-prefix-length', '8', '--min-prefix-length', '8',
self._subnet_pool.name,
] ]
verifylist = [ verifylist = [
('subnet_pool', self._subnet_pool.name),
('name', 'noob'), ('name', 'noob'),
('default_prefix_length', '8'), ('default_prefix_length', '8'),
('min_prefix_length', '8'), ('min_prefix_length', '8'),
('subnet_pool', self._subnet_pool.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -340,15 +373,15 @@ class TestSetSubnetPool(TestSubnetPool):
def test_set_that(self): def test_set_that(self):
arglist = [ arglist = [
self._subnet_pool.name,
'--pool-prefix', '10.0.1.0/24', '--pool-prefix', '10.0.1.0/24',
'--pool-prefix', '10.0.2.0/24', '--pool-prefix', '10.0.2.0/24',
'--max-prefix-length', '16', '--max-prefix-length', '16',
self._subnet_pool.name,
] ]
verifylist = [ verifylist = [
('subnet_pool', self._subnet_pool.name),
('prefixes', ['10.0.1.0/24', '10.0.2.0/24']), ('prefixes', ['10.0.1.0/24', '10.0.2.0/24']),
('max_prefix_length', '16'), ('max_prefix_length', '16'),
('subnet_pool', self._subnet_pool.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -374,17 +407,73 @@ class TestSetSubnetPool(TestSubnetPool):
def test_set_len_negative(self): def test_set_len_negative(self):
arglist = [ arglist = [
self._subnet_pool.name,
'--max-prefix-length', '-16', '--max-prefix-length', '-16',
self._subnet_pool.name,
] ]
verifylist = [ verifylist = [
('subnet_pool', self._subnet_pool.name),
('max_prefix_length', '-16'), ('max_prefix_length', '-16'),
('subnet_pool', self._subnet_pool.name),
] ]
self.assertRaises(argparse.ArgumentTypeError, self.check_parser, self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
self.cmd, arglist, verifylist) self.cmd, arglist, verifylist)
def test_set_address_scope(self):
arglist = [
'--address-scope', self._address_scope.id,
self._subnet_pool.name,
]
verifylist = [
('address_scope', self._address_scope.id),
('subnet_pool', self._subnet_pool.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'address_scope_id': self._address_scope.id,
}
self.network.update_subnet_pool.assert_called_once_with(
self._subnet_pool, **attrs)
self.assertIsNone(result)
def test_set_no_address_scope(self):
arglist = [
'--no-address-scope',
self._subnet_pool.name,
]
verifylist = [
('no_address_scope', True),
('subnet_pool', self._subnet_pool.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'address_scope_id': None,
}
self.network.update_subnet_pool.assert_called_once_with(
self._subnet_pool, **attrs)
self.assertIsNone(result)
def test_set_no_address_scope_conflict(self):
arglist = [
'--address-scope', self._address_scope.id,
'--no-address-scope',
self._subnet_pool.name,
]
verifylist = [
('address_scope', self._address_scope.id),
('no_address_scope', True),
('subnet_pool', self._subnet_pool.name),
]
# Exclusive arguments will conflict here.
self.assertRaises(tests_utils.ParserException, self.check_parser,
self.cmd, arglist, verifylist)
class TestShowSubnetPool(TestSubnetPool): class TestShowSubnetPool(TestSubnetPool):