Skip to content

Commit ffcfff6

Browse files
TerryHowelingxiankong
authored andcommitted
Subnet List
Subnet list command Partially implements: blueprint neutron-client Partial-Bug: #1523258 Change-Id: I3c0748074a6511ff92500516b3129886d2476eed
1 parent eb36df1 commit ffcfff6

6 files changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
======
2+
subnet
3+
======
4+
5+
Network v2
6+
7+
subnet list
8+
-----------
9+
10+
List subnets
11+
12+
.. program:: subnet list
13+
.. code:: bash
14+
15+
os subnet list
16+
[--long]
17+
18+
.. option:: --long
19+
20+
List additional fields in output

doc/source/commands.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ referring to both Compute and Volume quotas.
116116
* ``service``: (**Identity**) a cloud service
117117
* ``service provider``: (**Identity**) a resource that consumes assertions from an ``identity provider``
118118
* ``snapshot``: (**Volume**) a point-in-time copy of a volume
119+
* ``subnet``: (**Network**) - a pool of private IP addresses that can be assigned to instances or other resources
119120
* ``token``: (**Identity**) a bearer token managed by Identity service
120121
* ``usage``: (**Compute**) display host resources being consumed
121122
* ``user``: (**Identity**) individual cloud resources users
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
"""Subnet action implementations"""
15+
16+
import logging
17+
18+
from cliff import lister
19+
20+
from openstackclient.common import utils
21+
22+
23+
def _format_allocation_pools(data):
24+
pool_formatted = ['%s-%s' % (pool.get('start', ''), pool.get('end', ''))
25+
for pool in data]
26+
return ','.join(pool_formatted)
27+
28+
29+
_formatters = {
30+
'allocation_pools': _format_allocation_pools,
31+
'dns_nameservers': utils.format_list,
32+
'host_routes': utils.format_list,
33+
}
34+
35+
36+
class ListSubnet(lister.Lister):
37+
"""List subnets"""
38+
39+
log = logging.getLogger(__name__ + '.ListSubnet')
40+
41+
def get_parser(self, prog_name):
42+
parser = super(ListSubnet, self).get_parser(prog_name)
43+
parser.add_argument(
44+
'--long',
45+
action='store_true',
46+
default=False,
47+
help='List additional fields in output',
48+
)
49+
return parser
50+
51+
def take_action(self, parsed_args):
52+
self.log.debug('take_action(%s)' % parsed_args)
53+
54+
data = self.app.client_manager.network.subnets()
55+
56+
headers = ('ID', 'Name', 'Network', 'CIDR')
57+
columns = ('id', 'name', 'network_id', 'cidr')
58+
if parsed_args.long:
59+
headers += ('Project', 'DHCP', 'DNS Nameservers',
60+
'Allocation Pools', 'Host Routes', 'IP Version',
61+
'Gateway')
62+
columns += ('tenant_id', 'enable_dhcp', 'dns_nameservers',
63+
'allocation_pools', 'host_routes', 'ip_version',
64+
'gateway_ip')
65+
66+
return (headers,
67+
(utils.get_item_properties(
68+
s, columns,
69+
formatters=_formatters,
70+
) for s in data))

openstackclient/tests/network/v2/fakes.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,71 @@ def get_routers(routers=None, count=2):
304304
if routers is None:
305305
routers = FakeRouter.create_routers(count)
306306
return mock.MagicMock(side_effect=routers)
307+
308+
309+
class FakeSubnet(object):
310+
"""Fake one or more subnets."""
311+
312+
@staticmethod
313+
def create_one_subnet(attrs={}, methods={}):
314+
"""Create a fake subnet.
315+
316+
:param Dictionary attrs:
317+
A dictionary with all attributes
318+
:param Dictionary methods:
319+
A dictionary with all methods
320+
:return:
321+
A FakeResource object faking the subnet
322+
"""
323+
# Set default attributes.
324+
subnet_attrs = {
325+
'id': 'subnet-id-' + uuid.uuid4().hex,
326+
'name': 'subnet-name-' + uuid.uuid4().hex,
327+
'network_id': 'network-id-' + uuid.uuid4().hex,
328+
'cidr': '10.10.10.0/24',
329+
'tenant_id': 'project-id-' + uuid.uuid4().hex,
330+
'enable_dhcp': True,
331+
'dns_nameservers': [],
332+
'allocation_pools': [],
333+
'host_routes': [],
334+
'ip_version': '4',
335+
'gateway_ip': '10.10.10.1',
336+
}
337+
338+
# Overwrite default attributes.
339+
subnet_attrs.update(attrs)
340+
341+
# Set default methods.
342+
subnet_methods = {
343+
'keys': ['id', 'name', 'network_id', 'cidr', 'enable_dhcp',
344+
'allocation_pools', 'dns_nameservers', 'gateway_ip',
345+
'host_routes', 'ip_version', 'tenant_id']
346+
}
347+
348+
# Overwrite default methods.
349+
subnet_methods.update(methods)
350+
351+
subnet = fakes.FakeResource(info=copy.deepcopy(subnet_attrs),
352+
methods=copy.deepcopy(subnet_methods),
353+
loaded=True)
354+
355+
return subnet
356+
357+
@staticmethod
358+
def create_subnets(attrs={}, methods={}, count=2):
359+
"""Create multiple fake subnets.
360+
361+
:param Dictionary attrs:
362+
A dictionary with all attributes
363+
:param Dictionary methods:
364+
A dictionary with all methods
365+
:param int count:
366+
The number of subnets to fake
367+
:return:
368+
A list of FakeResource objects faking the subnets
369+
"""
370+
subnets = []
371+
for i in range(0, count):
372+
subnets.append(FakeSubnet.create_one_subnet(attrs, methods))
373+
374+
return subnets
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
import mock
15+
16+
from openstackclient.common import utils
17+
from openstackclient.network.v2 import subnet as subnet_v2
18+
from openstackclient.tests.network.v2 import fakes as network_fakes
19+
20+
21+
class TestSubnet(network_fakes.TestNetworkV2):
22+
def setUp(self):
23+
super(TestSubnet, self).setUp()
24+
25+
# Get a shortcut to the network client
26+
self.network = self.app.client_manager.network
27+
28+
29+
class TestListSubnet(TestSubnet):
30+
# The subnets going to be listed up.
31+
_subnet = network_fakes.FakeSubnet.create_subnets(count=3)
32+
33+
columns = (
34+
'ID',
35+
'Name',
36+
'Network',
37+
'CIDR'
38+
)
39+
columns_long = columns + (
40+
'Project',
41+
'DHCP',
42+
'DNS Nameservers',
43+
'Allocation Pools',
44+
'Host Routes',
45+
'IP Version',
46+
'Gateway'
47+
)
48+
49+
data = []
50+
for subnet in _subnet:
51+
data.append((
52+
subnet.id,
53+
subnet.name,
54+
subnet.network_id,
55+
subnet.cidr,
56+
))
57+
58+
data_long = []
59+
for subnet in _subnet:
60+
data_long.append((
61+
subnet.id,
62+
subnet.name,
63+
subnet.network_id,
64+
subnet.cidr,
65+
subnet.tenant_id,
66+
subnet.enable_dhcp,
67+
utils.format_list(subnet.dns_nameservers),
68+
subnet_v2._format_allocation_pools(subnet.allocation_pools),
69+
utils.format_list(subnet.host_routes),
70+
subnet.ip_version,
71+
subnet.gateway_ip
72+
))
73+
74+
def setUp(self):
75+
super(TestListSubnet, self).setUp()
76+
77+
# Get the command object to test
78+
self.cmd = subnet_v2.ListSubnet(self.app, self.namespace)
79+
80+
self.network.subnets = mock.Mock(return_value=self._subnet)
81+
82+
def test_subnet_list_no_options(self):
83+
arglist = []
84+
verifylist = [
85+
('long', False),
86+
]
87+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
88+
89+
columns, data = self.cmd.take_action(parsed_args)
90+
91+
self.network.subnets.assert_called_with()
92+
self.assertEqual(self.columns, columns)
93+
self.assertEqual(self.data, list(data))
94+
95+
def test_subnet_list_long(self):
96+
arglist = [
97+
'--long',
98+
]
99+
verifylist = [
100+
('long', True),
101+
]
102+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
103+
104+
columns, data = self.cmd.take_action(parsed_args)
105+
106+
self.network.subnets.assert_called_with()
107+
self.assertEqual(self.columns_long, columns)
108+
self.assertEqual(self.data_long, list(data))

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ openstack.network.v2 =
339339
router_list = openstackclient.network.v2.router:ListRouter
340340
router_set = openstackclient.network.v2.router:SetRouter
341341
router_show = openstackclient.network.v2.router:ShowRouter
342+
subnet_list = openstackclient.network.v2.subnet:ListSubnet
342343

343344
openstack.object_store.v1 =
344345
object_store_account_set = openstackclient.object.v1.account:SetAccount

0 commit comments

Comments
 (0)