summaryrefslogtreecommitdiff
path: root/openstackclient/network
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient/network')
-rw-r--r--openstackclient/network/common.py164
-rw-r--r--openstackclient/network/v2/floating_ip.py66
-rw-r--r--openstackclient/network/v2/network.py133
-rw-r--r--openstackclient/network/v2/port.py61
-rw-r--r--openstackclient/network/v2/router.py46
-rw-r--r--openstackclient/network/v2/security_group.py40
-rw-r--r--openstackclient/network/v2/subnet.py63
7 files changed, 483 insertions, 90 deletions
diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py
new file mode 100644
index 00000000..cc343c3c
--- /dev/null
+++ b/openstackclient/network/common.py
@@ -0,0 +1,164 @@
+# 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 abc
+import six
+
+from openstackclient.common import command
+
+
+@six.add_metaclass(abc.ABCMeta)
+class NetworkAndComputeCommand(command.Command):
+ """Network and Compute Command"""
+
+ def take_action(self, parsed_args):
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.take_action_network(self.app.client_manager.network,
+ parsed_args)
+ else:
+ return self.take_action_compute(self.app.client_manager.compute,
+ parsed_args)
+
+ def get_parser(self, prog_name):
+ self.log.debug('get_parser(%s)', prog_name)
+ parser = super(NetworkAndComputeCommand, self).get_parser(prog_name)
+ parser = self.update_parser_common(parser)
+ self.log.debug('common parser: %s', parser)
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.update_parser_network(parser)
+ else:
+ return self.update_parser_compute(parser)
+
+ def update_parser_common(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_network(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_compute(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ @abc.abstractmethod
+ def take_action_network(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
+
+ @abc.abstractmethod
+ def take_action_compute(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
+
+
+@six.add_metaclass(abc.ABCMeta)
+class NetworkAndComputeLister(command.Lister):
+ """Network and Compute Lister
+
+ Lister class for commands that support implementation via
+ the network or compute endpoint. Such commands have different
+ implementations for take_action() and may even have different
+ arguments.
+ """
+
+ def take_action(self, parsed_args):
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.take_action_network(self.app.client_manager.network,
+ parsed_args)
+ else:
+ return self.take_action_compute(self.app.client_manager.compute,
+ parsed_args)
+
+ def get_parser(self, prog_name):
+ self.log.debug('get_parser(%s)', prog_name)
+ parser = super(NetworkAndComputeLister, self).get_parser(prog_name)
+ parser = self.update_parser_common(parser)
+ self.log.debug('common parser: %s', parser)
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.update_parser_network(parser)
+ else:
+ return self.update_parser_compute(parser)
+
+ def update_parser_common(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_network(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_compute(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ @abc.abstractmethod
+ def take_action_network(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
+
+ @abc.abstractmethod
+ def take_action_compute(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
+
+
+@six.add_metaclass(abc.ABCMeta)
+class NetworkAndComputeShowOne(command.ShowOne):
+ """Network and Compute ShowOne
+
+ ShowOne class for commands that support implementation via
+ the network or compute endpoint. Such commands have different
+ implementations for take_action() and may even have different
+ arguments.
+ """
+
+ def take_action(self, parsed_args):
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.take_action_network(self.app.client_manager.network,
+ parsed_args)
+ else:
+ return self.take_action_compute(self.app.client_manager.compute,
+ parsed_args)
+
+ def get_parser(self, prog_name):
+ self.log.debug('get_parser(%s)', prog_name)
+ parser = super(NetworkAndComputeShowOne, self).get_parser(prog_name)
+ parser = self.update_parser_common(parser)
+ self.log.debug('common parser: %s', parser)
+ if self.app.client_manager.is_network_endpoint_enabled():
+ return self.update_parser_network(parser)
+ else:
+ return self.update_parser_compute(parser)
+
+ def update_parser_common(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_network(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ def update_parser_compute(self, parser):
+ """Default is no updates to parser."""
+ return parser
+
+ @abc.abstractmethod
+ def take_action_network(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
+
+ @abc.abstractmethod
+ def take_action_compute(self, client, parsed_args):
+ """Override to do something useful."""
+ pass
diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py
new file mode 100644
index 00000000..48895048
--- /dev/null
+++ b/openstackclient/network/v2/floating_ip.py
@@ -0,0 +1,66 @@
+# 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="<floating-ip>",
+ 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)
+
+
+class ListFloatingIP(common.NetworkAndComputeLister):
+ """List floating IP(s)"""
+
+ columns = ('ID', 'IP', 'Fixed IP', 'Instance ID', 'Pool')
+ column_headers = ('ID', 'Floating IP', 'Fixed IP', 'Server ID', 'Pool')
+
+ def take_action_network(self, client, parsed_args):
+ query = {}
+ data = client.ips(**query)
+
+ return (self.column_headers,
+ (utils.get_item_properties(
+ s, self.columns,
+ formatters={},
+ ) for s in data))
+
+ def take_action_compute(self, client, parsed_args):
+ data = client.floating_ips.list()
+
+ return (self.column_headers,
+ (utils.get_item_properties(
+ s, self.columns,
+ formatters={},
+ ) for s in data))
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index 38dff8d9..636c333e 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -13,15 +13,11 @@
"""Network action implementations"""
-import logging
-
-from cliff import command
-from cliff import lister
-from cliff import show
-
+from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.identity import common as identity_common
+from openstackclient.network import common
def _format_admin_state(item):
@@ -36,6 +32,8 @@ _formatters = {
'subnets': utils.format_list,
'admin_state_up': _format_admin_state,
'router_external': _format_router_external,
+ 'availability_zones': utils.format_list,
+ 'availability_zone_hints': utils.format_list,
}
@@ -50,10 +48,35 @@ def _get_columns(item):
return tuple(sorted(columns))
-class CreateNetwork(show.ShowOne):
- """Create new network"""
+def _get_attrs(client_manager, parsed_args):
+ attrs = {}
+ if parsed_args.name is not None:
+ attrs['name'] = str(parsed_args.name)
+ if parsed_args.admin_state is not None:
+ attrs['admin_state_up'] = parsed_args.admin_state
+ if parsed_args.shared is not None:
+ attrs['shared'] = parsed_args.shared
+
+ # "network set" command doesn't support setting project.
+ if 'project' in parsed_args and parsed_args.project is not None:
+ identity_client = client_manager.identity
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ attrs['tenant_id'] = project_id
+
+ # "network set" command doesn't support setting availability zone hints.
+ if 'availability_zone_hints' in parsed_args and \
+ parsed_args.availability_zone_hints is not None:
+ attrs['availability_zone_hints'] = parsed_args.availability_zone_hints
+
+ return attrs
+
- log = logging.getLogger(__name__ + '.CreateNetwork')
+class CreateNetwork(command.ShowOne):
+ """Create new network"""
def get_parser(self, prog_name):
parser = super(CreateNetwork, self).get_parser(prog_name)
@@ -93,42 +116,36 @@ class CreateNetwork(show.ShowOne):
parser.add_argument(
'--project',
metavar='<project>',
- help="Owner's project (name or ID)")
+ help="Owner's project (name or ID)"
+ )
identity_common.add_project_domain_option_to_parser(parser)
+
+ parser.add_argument(
+ '--availability-zone-hint',
+ action='append',
+ dest='availability_zone_hints',
+ metavar='<availability-zone>',
+ help='Availability Zone in which to create this network '
+ '(requires the Network Availability Zone extension, '
+ 'this option can be repeated).',
+ )
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
- body = self.get_body(parsed_args)
- obj = client.create_network(**body)
+
+ attrs = _get_attrs(self.app.client_manager, parsed_args)
+ obj = client.create_network(**attrs)
columns = _get_columns(obj)
+
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
- def get_body(self, parsed_args):
- body = {'name': str(parsed_args.name),
- 'admin_state_up': parsed_args.admin_state}
- if parsed_args.shared is not None:
- body['shared'] = parsed_args.shared
- if parsed_args.project is not None:
- identity_client = self.app.client_manager.identity
- project_id = identity_common.find_project(
- identity_client,
- parsed_args.project,
- parsed_args.project_domain,
- ).id
- body['tenant_id'] = project_id
- return body
-
-
-class DeleteNetwork(command.Command):
- """Delete network(s)"""
- log = logging.getLogger(__name__ + '.DeleteNetwork')
+class DeleteNetwork(common.NetworkAndComputeCommand):
+ """Delete network(s)"""
- def get_parser(self, prog_name):
- parser = super(DeleteNetwork, self).get_parser(prog_name)
+ def update_parser_common(self, parser):
parser.add_argument(
'network',
metavar="<network>",
@@ -137,19 +154,23 @@ class DeleteNetwork(command.Command):
)
return parser
- def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
- client = self.app.client_manager.network
+ def take_action_network(self, client, parsed_args):
for network in parsed_args.network:
obj = client.find_network(network)
client.delete_network(obj)
+ def take_action_compute(self, client, parsed_args):
+ for network in parsed_args.network:
+ network = utils.find_resource(
+ client.networks,
+ network,
+ )
+ client.networks.delete(network.id)
+
-class ListNetwork(lister.Lister):
+class ListNetwork(command.Lister):
"""List networks"""
- log = logging.getLogger(__name__ + '.ListNetwork')
-
def get_parser(self, prog_name):
parser = super(ListNetwork, self).get_parser(prog_name)
parser.add_argument(
@@ -167,7 +188,6 @@ class ListNetwork(lister.Lister):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
if parsed_args.long:
@@ -181,6 +201,7 @@ class ListNetwork(lister.Lister):
'subnets',
'provider_network_type',
'router_external',
+ 'availability_zones',
)
column_headers = (
'ID',
@@ -192,6 +213,7 @@ class ListNetwork(lister.Lister):
'Subnets',
'Network Type',
'Router Type',
+ 'Availability Zones',
)
else:
columns = (
@@ -220,12 +242,10 @@ class ListNetwork(lister.Lister):
class SetNetwork(command.Command):
"""Set network properties"""
- log = logging.getLogger(__name__ + '.SetNetwork')
-
def get_parser(self, prog_name):
parser = super(SetNetwork, self).get_parser(prog_name)
parser.add_argument(
- 'identifier',
+ 'network',
metavar="<network>",
help=("Network to modify (name or ID)")
)
@@ -265,42 +285,33 @@ class SetNetwork(command.Command):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
- obj = client.find_network(parsed_args.identifier, ignore_missing=False)
+ obj = client.find_network(parsed_args.network, ignore_missing=False)
- if parsed_args.name is not None:
- obj.name = str(parsed_args.name)
- if parsed_args.admin_state is not None:
- obj.admin_state_up = parsed_args.admin_state
- if parsed_args.shared is not None:
- obj.shared = parsed_args.shared
-
- if not obj.is_dirty:
+ attrs = _get_attrs(self.app.client_manager, parsed_args)
+ if attrs == {}:
msg = "Nothing specified to be set"
raise exceptions.CommandError(msg)
- client.update_network(obj)
+ client.update_network(obj, **attrs)
+ return
-class ShowNetwork(show.ShowOne):
+class ShowNetwork(command.ShowOne):
"""Show network details"""
- log = logging.getLogger(__name__ + '.ShowNetwork')
-
def get_parser(self, prog_name):
parser = super(ShowNetwork, self).get_parser(prog_name)
parser.add_argument(
- 'identifier',
+ 'network',
metavar="<network>",
help=("Network to display (name or ID)")
)
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
- obj = client.find_network(parsed_args.identifier, ignore_missing=False)
+ obj = client.find_network(parsed_args.network, ignore_missing=False)
columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index ad906a28..46cb031f 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -13,16 +13,48 @@
"""Port action implementations"""
-import logging
+from openstackclient.common import command
+from openstackclient.common import utils
-from cliff import command
+
+def _format_admin_state(state):
+ return 'UP' if state else 'DOWN'
+
+
+_formatters = {
+ 'admin_state_up': _format_admin_state,
+ 'allowed_address_pairs': utils.format_list_of_dicts,
+ 'binding_profile': utils.format_dict,
+ 'binding_vif_details': utils.format_dict,
+ 'dns_assignment': utils.format_list_of_dicts,
+ 'extra_dhcp_opts': utils.format_list_of_dicts,
+ 'fixed_ips': utils.format_list_of_dicts,
+ 'security_groups': utils.format_list,
+}
+
+
+def _get_columns(item):
+ columns = item.keys()
+ if 'tenant_id' in columns:
+ columns.remove('tenant_id')
+ columns.append('project_id')
+ binding_columns = [
+ 'binding:host_id',
+ 'binding:profile',
+ 'binding:vif_details',
+ 'binding:vif_type',
+ 'binding:vnic_type',
+ ]
+ for binding_column in binding_columns:
+ if binding_column in columns:
+ columns.remove(binding_column)
+ columns.append(binding_column.replace('binding:', 'binding_', 1))
+ return sorted(columns)
class DeletePort(command.Command):
"""Delete port(s)"""
- log = logging.getLogger(__name__ + '.DeletePort')
-
def get_parser(self, prog_name):
parser = super(DeletePort, self).get_parser(prog_name)
parser.add_argument(
@@ -34,9 +66,28 @@ class DeletePort(command.Command):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
for port in parsed_args.port:
res = client.find_port(port)
client.delete_port(res)
+
+
+class ShowPort(command.ShowOne):
+ """Display port details"""
+
+ def get_parser(self, prog_name):
+ parser = super(ShowPort, self).get_parser(prog_name)
+ parser.add_argument(
+ 'port',
+ metavar="<port>",
+ help="Port to display (name or ID)"
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_port(parsed_args.port, ignore_missing=False)
+ columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters=_formatters)
+ return (tuple(columns), data)
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index 09e0fe4c..60db816a 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -14,12 +14,8 @@
"""Router action implementations"""
import json
-import logging
-
-from cliff import command
-from cliff import lister
-from cliff import show
+from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.identity import common as identity_common
@@ -39,6 +35,8 @@ def _format_external_gateway_info(info):
_formatters = {
'admin_state_up': _format_admin_state,
'external_gateway_info': _format_external_gateway_info,
+ 'availability_zones': utils.format_list,
+ 'availability_zone_hints': utils.format_list,
}
@@ -50,6 +48,9 @@ def _get_attrs(client_manager, parsed_args):
attrs['admin_state_up'] = parsed_args.admin_state_up
if parsed_args.distributed is not None:
attrs['distributed'] = parsed_args.distributed
+ if ('availability_zone_hints' in parsed_args
+ and parsed_args.availability_zone_hints is not None):
+ attrs['availability_zone_hints'] = parsed_args.availability_zone_hints
# "router set" command doesn't support setting project.
if 'project' in parsed_args and parsed_args.project is not None:
identity_client = client_manager.identity
@@ -67,11 +68,9 @@ def _get_attrs(client_manager, parsed_args):
return attrs
-class CreateRouter(show.ShowOne):
+class CreateRouter(command.ShowOne):
"""Create a new router"""
- log = logging.getLogger(__name__ + '.CreateRouter')
-
def get_parser(self, prog_name):
parser = super(CreateRouter, self).get_parser(prog_name)
parser.add_argument(
@@ -102,14 +101,23 @@ class CreateRouter(show.ShowOne):
)
parser.add_argument(
'--project',
- metavar='<poroject>',
+ metavar='<project>',
help="Owner's project (name or ID)",
)
+ parser.add_argument(
+ '--availability-zone-hint',
+ metavar='<availability-zone>',
+ action='append',
+ dest='availability_zone_hints',
+ help='Availability Zone in which to create this router '
+ '(requires the Router Availability Zone extension, '
+ 'this option can be repeated).',
+ )
+
identity_common.add_project_domain_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
@@ -128,8 +136,6 @@ class CreateRouter(show.ShowOne):
class DeleteRouter(command.Command):
"""Delete router(s)"""
- log = logging.getLogger(__name__ + '.DeleteRouter')
-
def get_parser(self, prog_name):
parser = super(DeleteRouter, self).get_parser(prog_name)
parser.add_argument(
@@ -141,18 +147,15 @@ class DeleteRouter(command.Command):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
for router in parsed_args.router:
obj = client.find_router(router)
client.delete_router(obj)
-class ListRouter(lister.Lister):
+class ListRouter(command.Lister):
"""List routers"""
- log = logging.getLogger(__name__ + '.ListRouter')
-
def get_parser(self, prog_name):
parser = super(ListRouter, self).get_parser(prog_name)
parser.add_argument(
@@ -164,7 +167,6 @@ class ListRouter(lister.Lister):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
columns = (
@@ -189,10 +191,12 @@ class ListRouter(lister.Lister):
columns = columns + (
'routes',
'external_gateway_info',
+ 'availability_zones'
)
column_headers = column_headers + (
'Routes',
'External gateway info',
+ 'Availability zones'
)
data = client.routers()
@@ -206,8 +210,6 @@ class ListRouter(lister.Lister):
class SetRouter(command.Command):
"""Set router properties"""
- log = logging.getLogger(__name__ + '.SetRouter')
-
def get_parser(self, prog_name):
parser = super(SetRouter, self).get_parser(prog_name)
parser.add_argument(
@@ -262,7 +264,6 @@ class SetRouter(command.Command):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
obj = client.find_router(parsed_args.router, ignore_missing=False)
@@ -274,11 +275,9 @@ class SetRouter(command.Command):
client.update_router(obj, **attrs)
-class ShowRouter(show.ShowOne):
+class ShowRouter(command.ShowOne):
"""Display router details"""
- log = logging.getLogger(__name__ + '.ShowRouter')
-
def get_parser(self, prog_name):
parser = super(ShowRouter, self).get_parser(prog_name)
parser.add_argument(
@@ -289,7 +288,6 @@ class ShowRouter(show.ShowOne):
return parser
def take_action(self, parsed_args):
- self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
obj = client.find_router(parsed_args.router, ignore_missing=False)
columns = sorted(obj.keys())
diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py
new file mode 100644
index 00000000..4e122f21
--- /dev/null
+++ b/openstackclient/network/v2/security_group.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.
+#
+
+"""Security Group action implementations"""
+
+from openstackclient.common import utils
+from openstackclient.network import common
+
+
+class DeleteSecurityGroup(common.NetworkAndComputeCommand):
+ """Delete a security group"""
+
+ def update_parser_common(self, parser):
+ parser.add_argument(
+ 'group',
+ metavar='<group>',
+ help='Security group to delete (name or ID)',
+ )
+ return parser
+
+ def take_action_network(self, client, parsed_args):
+ obj = client.find_security_group(parsed_args.group)
+ client.delete_security_group(obj)
+
+ def take_action_compute(self, client, parsed_args):
+ data = utils.find_resource(
+ client.security_groups,
+ parsed_args.group,
+ )
+ client.security_groups.delete(data.id)
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
new file mode 100644
index 00000000..b948c656
--- /dev/null
+++ b/openstackclient/network/v2/subnet.py
@@ -0,0 +1,63 @@
+# 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.
+#
+
+"""Subnet action implementations"""
+
+from openstackclient.common import command
+from openstackclient.common import utils
+
+
+def _format_allocation_pools(data):
+ pool_formatted = ['%s-%s' % (pool.get('start', ''), pool.get('end', ''))
+ for pool in data]
+ return ','.join(pool_formatted)
+
+
+_formatters = {
+ 'allocation_pools': _format_allocation_pools,
+ 'dns_nameservers': utils.format_list,
+ 'host_routes': utils.format_list,
+}
+
+
+class ListSubnet(command.Lister):
+ """List subnets"""
+
+ def get_parser(self, prog_name):
+ parser = super(ListSubnet, self).get_parser(prog_name)
+ parser.add_argument(
+ '--long',
+ action='store_true',
+ default=False,
+ help='List additional fields in output',
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ data = self.app.client_manager.network.subnets()
+
+ headers = ('ID', 'Name', 'Network', 'Subnet')
+ columns = ('id', 'name', 'network_id', 'cidr')
+ if parsed_args.long:
+ headers += ('Project', 'DHCP', 'Name Servers',
+ 'Allocation Pools', 'Host Routes', 'IP Version',
+ 'Gateway')
+ columns += ('tenant_id', 'enable_dhcp', 'dns_nameservers',
+ 'allocation_pools', 'host_routes', 'ip_version',
+ 'gateway_ip')
+
+ return (headers,
+ (utils.get_item_properties(
+ s, columns,
+ formatters=_formatters,
+ ) for s in data))