summaryrefslogtreecommitdiff
path: root/openstackclient/network/v2
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient/network/v2')
-rw-r--r--openstackclient/network/v2/subnet.py226
1 files changed, 223 insertions, 3 deletions
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index 9e53ee84..794c787f 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -12,9 +12,14 @@
#
"""Subnet action implementations"""
+import copy
+
+from json.encoder import JSONEncoder
from openstackclient.common import command
+from openstackclient.common import parseractions
from openstackclient.common import utils
+from openstackclient.identity import common as identity_common
def _format_allocation_pools(data):
@@ -23,10 +28,17 @@ def _format_allocation_pools(data):
return ','.join(pool_formatted)
+def _format_host_routes(data):
+ try:
+ return '\n'.join([JSONEncoder().encode(route) for route in data])
+ except (TypeError, KeyError):
+ return ''
+
+
_formatters = {
'allocation_pools': _format_allocation_pools,
'dns_nameservers': utils.format_list,
- 'host_routes': utils.format_list,
+ 'host_routes': _format_host_routes,
}
@@ -38,6 +50,214 @@ def _get_columns(item):
return tuple(sorted(columns))
+def convert_entries_to_nexthop(entries):
+ # Change 'gateway' entry to 'nexthop'
+ changed_entries = copy.deepcopy(entries)
+ for entry in changed_entries:
+ entry['nexthop'] = entry['gateway']
+ del entry['gateway']
+
+ return changed_entries
+
+
+def convert_entries_to_gateway(entries):
+ # Change 'nexhop' entry to 'gateway'
+ changed_entries = copy.deepcopy(entries)
+ for entry in changed_entries:
+ entry['gateway'] = entry['nexthop']
+ del entry['nexthop']
+
+ return changed_entries
+
+
+def _get_attrs(client_manager, parsed_args):
+ attrs = {}
+ if parsed_args.name is not None:
+ attrs['name'] = str(parsed_args.name)
+
+ 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
+
+ client = client_manager.network
+ attrs['network_id'] = client.find_network(parsed_args.network,
+ ignore_missing=False).id
+
+ if parsed_args.subnet_pool is not None:
+ subnet_pool = client.find_subnet_pool(parsed_args.subnet_pool,
+ ignore_missing=False)
+ attrs['subnetpool_id'] = subnet_pool.id
+
+ if parsed_args.use_default_subnet_pool:
+ attrs['use_default_subnetpool'] = True
+ if parsed_args.gateway.lower() != 'auto':
+ if parsed_args.gateway.lower() == 'none':
+ attrs['gateway_ip'] = None
+ else:
+ attrs['gateway_ip'] = parsed_args.gateway
+ if parsed_args.prefix_length is not None:
+ attrs['prefixlen'] = parsed_args.prefix_length
+ if parsed_args.subnet_range is not None:
+ attrs['cidr'] = parsed_args.subnet_range
+ if parsed_args.ip_version is not None:
+ attrs['ip_version'] = parsed_args.ip_version
+ if parsed_args.ipv6_ra_mode is not None:
+ attrs['ipv6_ra_mode'] = parsed_args.ipv6_ra_mode
+ if parsed_args.ipv6_address_mode is not None:
+ attrs['ipv6_address_mode'] = parsed_args.ipv6_address_mode
+ if parsed_args.allocation_pools is not None:
+ attrs['allocation_pools'] = parsed_args.allocation_pools
+ if parsed_args.enable_dhcp is not None:
+ attrs['enable_dhcp'] = parsed_args.enable_dhcp
+ if parsed_args.dns_nameservers is not None:
+ attrs['dns_nameservers'] = parsed_args.dns_nameservers
+ if parsed_args.host_routes is not None:
+ # Change 'gateway' entry to 'nexthop' to match the API
+ attrs['host_routes'] = convert_entries_to_nexthop(
+ parsed_args.host_routes)
+
+ return attrs
+
+
+class CreateSubnet(command.ShowOne):
+ """Create a subnet"""
+
+ def get_parser(self, prog_name):
+ parser = super(CreateSubnet, self).get_parser(prog_name)
+ parser.add_argument(
+ 'name',
+ help='New subnet name',
+ )
+ parser.add_argument(
+ '--project',
+ metavar='<project>',
+ help="Owner's project (name or ID)",
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
+ subnet_pool_group = parser.add_mutually_exclusive_group()
+ subnet_pool_group.add_argument(
+ '--subnet-pool',
+ metavar='<subnet-pool>',
+ help='Subnet pool from which this subnet will obtain a CIDR '
+ '(Name or ID)',
+ )
+ subnet_pool_group.add_argument(
+ '--use-default-subnet-pool',
+ action='store_true',
+ help='Use default subnet pool for --ip-version',
+ )
+ parser.add_argument(
+ '--prefix-length',
+ metavar='<prefix-length>',
+ help='Prefix length for subnet allocation from subnetpool',
+ )
+ parser.add_argument(
+ '--subnet-range',
+ metavar='<subnet-range>',
+ help='Subnet range in CIDR notation '
+ '(required if --subnet-pool is not specified, '
+ 'optional otherwise)',
+ )
+ parser.add_argument(
+ '--allocation-pool',
+ metavar='start=<ip-address>,end=<ip-address>',
+ dest='allocation_pools',
+ action=parseractions.MultiKeyValueAction,
+ required_keys=['start', 'end'],
+ help='Allocation pool IP addresses for this subnet '
+ 'e.g.: start=192.168.199.2,end=192.168.199.254 '
+ '(This option can be repeated)',
+ )
+ dhcp_enable_group = parser.add_mutually_exclusive_group()
+ dhcp_enable_group.add_argument(
+ '--dhcp',
+ dest='enable_dhcp',
+ action='store_true',
+ default=True,
+ help='Enable DHCP (default)',
+ )
+ dhcp_enable_group.add_argument(
+ '--no-dhcp',
+ dest='enable_dhcp',
+ action='store_false',
+ help='Disable DHCP',
+ )
+ parser.add_argument(
+ '--dns-nameserver',
+ metavar='<dns-nameserver>',
+ action='append',
+ dest='dns_nameservers',
+ help='DNS name server for this subnet '
+ '(This option can be repeated)',
+ )
+ parser.add_argument(
+ '--gateway',
+ metavar='<gateway>',
+ default='auto',
+ help="Specify a gateway for the subnet. The three options are: "
+ " <ip-address>: Specific IP address to use as the gateway "
+ " 'auto': Gateway address should automatically be "
+ " chosen from within the subnet itself "
+ " 'none': This subnet will not use a gateway "
+ "e.g.: --gateway 192.168.9.1, --gateway auto, --gateway none"
+ "(default is 'auto')",
+ )
+ parser.add_argument(
+ '--host-route',
+ metavar='destination=<subnet>,gateway=<ip-address>',
+ dest='host_routes',
+ action=parseractions.MultiKeyValueAction,
+ required_keys=['destination', 'gateway'],
+ help='Additional route for this subnet '
+ 'e.g.: destination=10.10.0.0/16,gateway=192.168.71.254 '
+ 'destination: destination subnet (in CIDR notation) '
+ 'gateway: nexthop IP address '
+ '(This option can be repeated)',
+ )
+ parser.add_argument(
+ '--ip-version',
+ type=int,
+ default=4,
+ choices=[4, 6],
+ help='IP version (default is 4). Note that when subnet pool is '
+ 'specified, IP version is determined from the subnet pool '
+ 'and this option is ignored.',
+ )
+ parser.add_argument(
+ '--ipv6-ra-mode',
+ choices=['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'],
+ help='IPv6 RA (Router Advertisement) mode, '
+ 'valid modes: [dhcpv6-stateful, dhcpv6-stateless, slaac]',
+ )
+ parser.add_argument(
+ '--ipv6-address-mode',
+ choices=['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'],
+ help='IPv6 address mode, '
+ 'valid modes: [dhcpv6-stateful, dhcpv6-stateless, slaac]',
+ )
+ parser.add_argument(
+ '--network',
+ required=True,
+ metavar='<network>',
+ help='Network this subnet belongs to (name or ID)',
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ attrs = _get_attrs(self.app.client_manager, parsed_args)
+ obj = client.create_subnet(**attrs)
+ columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters=_formatters)
+ return (columns, data)
+
+
class DeleteSubnet(command.Command):
"""Delete subnet"""
@@ -46,7 +266,7 @@ class DeleteSubnet(command.Command):
parser.add_argument(
'subnet',
metavar="<subnet>",
- help="Subnet to delete (name or ID)"
+ help="Subnet to delete (name or ID)",
)
return parser
@@ -97,7 +317,7 @@ class ShowSubnet(command.ShowOne):
parser.add_argument(
'subnet',
metavar="<subnet>",
- help="Subnet to show (name or ID)"
+ help="Subnet to show (name or ID)",
)
return parser