summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/common/exceptions.py25
-rw-r--r--openstackclient/compute/v2/floatingip.py23
-rw-r--r--openstackclient/compute/v2/security_group.py65
-rw-r--r--openstackclient/compute/v2/service.py4
-rw-r--r--openstackclient/network/v2/floating_ip.py83
-rw-r--r--openstackclient/network/v2/security_group_rule.py108
-rw-r--r--openstackclient/network/v2/subnet.py215
-rw-r--r--openstackclient/network/v2/subnet_pool.py6
-rw-r--r--openstackclient/tests/compute/v2/fakes.py6
-rw-r--r--openstackclient/tests/compute/v2/test_security_group_rule.py266
-rw-r--r--openstackclient/tests/network/v2/fakes.py10
-rw-r--r--openstackclient/tests/network/v2/test_floating_ip.py166
-rw-r--r--openstackclient/tests/network/v2/test_security_group_rule.py319
-rw-r--r--openstackclient/tests/network/v2/test_subnet.py74
-rw-r--r--openstackclient/tests/network/v2/test_subnet_pool.py12
-rw-r--r--openstackclient/volume/v1/volume.py46
-rw-r--r--openstackclient/volume/v1/volume_type.py50
-rw-r--r--openstackclient/volume/v2/volume.py66
-rw-r--r--openstackclient/volume/v2/volume_type.py10
19 files changed, 986 insertions, 568 deletions
diff --git a/openstackclient/common/exceptions.py b/openstackclient/common/exceptions.py
index ee0f7a11..5f81e6a6 100644
--- a/openstackclient/common/exceptions.py
+++ b/openstackclient/common/exceptions.py
@@ -108,28 +108,3 @@ _code_map = dict((c.http_status, c) for c in [
OverLimit,
HTTPNotImplemented
])
-
-
-def from_response(response, body):
- """Return an instance of a ClientException based on an httplib2 response.
-
- Usage::
-
- resp, body = http.request(...)
- if resp.status != 200:
- raise exception_from_response(resp, body)
- """
- cls = _code_map.get(response.status, ClientException)
- if body:
- if hasattr(body, 'keys'):
- error = body[list(body.keys())[0]]
- message = error.get('message')
- details = error.get('details')
- else:
- # If we didn't get back a properly formed error message we
- # probably couldn't communicate with Keystone at all.
- message = "Unable to communicate with image service: %s." % body
- details = None
- return cls(code=response.status, message=message, details=details)
- else:
- return cls(code=response.status)
diff --git a/openstackclient/compute/v2/floatingip.py b/openstackclient/compute/v2/floatingip.py
index 6212989f..fac4d2e3 100644
--- a/openstackclient/compute/v2/floatingip.py
+++ b/openstackclient/compute/v2/floatingip.py
@@ -15,8 +15,6 @@
"""Floating IP action implementations"""
-import six
-
from openstackclient.common import command
from openstackclient.common import utils
@@ -47,27 +45,6 @@ class AddFloatingIP(command.Command):
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):
"""Remove floating IP address from server"""
diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py
index 734bd78e..ca3bf5dc 100644
--- a/openstackclient/compute/v2/security_group.py
+++ b/openstackclient/compute/v2/security_group.py
@@ -16,15 +16,12 @@
"""Compute v2 Security Group action implementations"""
-import six
-
try:
from novaclient.v2 import security_group_rules
except ImportError:
from novaclient.v1_1 import security_group_rules
from openstackclient.common import command
-from openstackclient.common import parseractions
from openstackclient.common import utils
@@ -56,68 +53,6 @@ def _xform_security_group_rule(sgroup):
return info
-class CreateSecurityGroupRule(command.ShowOne):
- """Create a new security group rule"""
-
- def get_parser(self, prog_name):
- parser = super(CreateSecurityGroupRule, self).get_parser(prog_name)
- parser.add_argument(
- 'group',
- metavar='<group>',
- help='Create rule in this security group (name or ID)',
- )
- parser.add_argument(
- "--proto",
- metavar="<proto>",
- default="tcp",
- help="IP protocol (icmp, tcp, udp; default: tcp)",
- )
- source_group = parser.add_mutually_exclusive_group()
- source_group.add_argument(
- "--src-ip",
- metavar="<ip-address>",
- default="0.0.0.0/0",
- help="Source IP address block (may use CIDR notation; default: "
- "0.0.0.0/0)",
- )
- source_group.add_argument(
- "--src-group",
- metavar="<group>",
- help="Source security group (ID only)",
- )
- parser.add_argument(
- "--dst-port",
- metavar="<port-range>",
- default=(0, 0),
- action=parseractions.RangeAction,
- help="Destination port, may be a range: 137:139 (default: 0; "
- "only required for proto tcp and udp)",
- )
- return parser
-
- def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
- group = utils.find_resource(
- compute_client.security_groups,
- parsed_args.group,
- )
- if parsed_args.proto.lower() == 'icmp':
- from_port, to_port = -1, -1
- else:
- from_port, to_port = parsed_args.dst_port
- data = compute_client.security_group_rules.create(
- group.id,
- parsed_args.proto,
- from_port,
- to_port,
- parsed_args.src_ip,
- parsed_args.src_group,
- )
-
- info = _xform_security_group_rule(data._info)
- return zip(*sorted(six.iteritems(info)))
-
-
class ListSecurityGroupRule(command.Lister):
"""List security group rules"""
diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py
index 89f5cad9..68037c94 100644
--- a/openstackclient/compute/v2/service.py
+++ b/openstackclient/compute/v2/service.py
@@ -44,11 +44,11 @@ class ListService(command.Lister):
parser.add_argument(
"--host",
metavar="<host>",
- help="Name of host")
+ help="List services on specified host (name only)")
parser.add_argument(
"--service",
metavar="<service>",
- help="Name of service")
+ help="List only specified service (name only)")
parser.add_argument(
"--long",
action="store_true",
diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py
index 16f2b574..b21d6e96 100644
--- a/openstackclient/network/v2/floating_ip.py
+++ b/openstackclient/network/v2/floating_ip.py
@@ -25,6 +25,89 @@ def _get_columns(item):
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):
"""Delete floating IP"""
diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py
index 9309b326..f60995ab 100644
--- a/openstackclient/network/v2/security_group_rule.py
+++ b/openstackclient/network/v2/security_group_rule.py
@@ -16,6 +16,7 @@
import six
from openstackclient.common import exceptions
+from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.network import common
from openstackclient.network import utils as network_utils
@@ -34,6 +35,113 @@ def _get_columns(item):
return tuple(sorted(columns))
+def _convert_to_lowercase(string):
+ return string.lower()
+
+
+class CreateSecurityGroupRule(common.NetworkAndComputeShowOne):
+ """Create a new security group rule"""
+
+ def update_parser_common(self, parser):
+ parser.add_argument(
+ 'group',
+ metavar='<group>',
+ help='Create rule in this security group (name or ID)',
+ )
+ # TODO(rtheis): Add support for additional protocols for network.
+ # Until then, continue enforcing the compute choices.
+ parser.add_argument(
+ "--proto",
+ metavar="<proto>",
+ default="tcp",
+ choices=['icmp', 'tcp', 'udp'],
+ type=_convert_to_lowercase,
+ help="IP protocol (icmp, tcp, udp; default: tcp)",
+ )
+ source_group = parser.add_mutually_exclusive_group()
+ source_group.add_argument(
+ "--src-ip",
+ metavar="<ip-address>",
+ default="0.0.0.0/0",
+ help="Source IP address block (may use CIDR notation; default: "
+ "0.0.0.0/0)",
+ )
+ source_group.add_argument(
+ "--src-group",
+ metavar="<group>",
+ help="Source security group (name or ID)",
+ )
+ parser.add_argument(
+ "--dst-port",
+ metavar="<port-range>",
+ default=(0, 0),
+ action=parseractions.RangeAction,
+ help="Destination port, may be a single port or port range: "
+ "137:139 (only required for IP protocols tcp and udp)",
+ )
+ return parser
+
+ def take_action_network(self, client, parsed_args):
+ # Get the security group ID to hold the rule.
+ security_group_id = client.find_security_group(
+ parsed_args.group,
+ ignore_missing=False
+ ).id
+
+ # Build the create attributes.
+ attrs = {}
+ # TODO(rtheis): Add --direction option. Until then, continue
+ # with the default of 'ingress'.
+ attrs['direction'] = 'ingress'
+ # TODO(rtheis): Add --ethertype option. Until then, continue
+ # with the default of 'IPv4'
+ attrs['ethertype'] = 'IPv4'
+ # TODO(rtheis): Add port range support (type and code) for icmp
+ # protocol. Until then, continue ignoring the port range.
+ if parsed_args.proto != 'icmp':
+ attrs['port_range_min'] = parsed_args.dst_port[0]
+ attrs['port_range_max'] = parsed_args.dst_port[1]
+ attrs['protocol'] = parsed_args.proto
+ if parsed_args.src_group is not None:
+ attrs['remote_group_id'] = client.find_security_group(
+ parsed_args.src_group,
+ ignore_missing=False
+ ).id
+ else:
+ attrs['remote_ip_prefix'] = parsed_args.src_ip
+ attrs['security_group_id'] = security_group_id
+
+ # Create and show the security group rule.
+ obj = client.create_security_group_rule(**attrs)
+ columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns)
+ return (columns, data)
+
+ def take_action_compute(self, client, parsed_args):
+ group = utils.find_resource(
+ client.security_groups,
+ parsed_args.group,
+ )
+ if parsed_args.proto == 'icmp':
+ from_port, to_port = -1, -1
+ else:
+ from_port, to_port = parsed_args.dst_port
+ if parsed_args.src_group is not None:
+ parsed_args.src_group = utils.find_resource(
+ client.security_groups,
+ parsed_args.src_group,
+ ).id
+ obj = client.security_group_rules.create(
+ group.id,
+ parsed_args.proto,
+ from_port,
+ to_port,
+ parsed_args.src_ip,
+ parsed_args.src_group,
+ )
+ return _format_security_group_rule_show(obj._info)
+
+
class DeleteSecurityGroupRule(common.NetworkAndComputeCommand):
"""Delete a security group rule"""
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index 794c787f..da4f6536 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -17,6 +17,7 @@ import copy
from json.encoder import JSONEncoder
from openstackclient.common import command
+from openstackclient.common import exceptions
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.identity import common as identity_common
@@ -42,6 +43,39 @@ _formatters = {
}
+def _get_common_parse_arguments(parser):
+ 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)',
+ )
+ 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(
+ '--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)',
+ )
+
+
def _get_columns(item):
columns = list(item.keys())
if 'tenant_id' in columns:
@@ -70,57 +104,66 @@ def convert_entries_to_gateway(entries):
return changed_entries
-def _get_attrs(client_manager, parsed_args):
+def _get_attrs(client_manager, parsed_args, is_create=True):
attrs = {}
- if parsed_args.name is not None:
+ if 'name' in parsed_args and 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:
+ if is_create:
+ 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.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 'gateway' in parsed_args and parsed_args.gateway is not None:
+ gateway = parsed_args.gateway.lower()
+
+ if not is_create and gateway == 'auto':
+ raise exceptions.CommandError("Auto option is not available"
+ " for Subnet Set. Valid options are"
+ " <ip-address> or none")
+ elif gateway != 'auto':
+ if gateway == 'none':
+ attrs['gateway_ip'] = None
+ else:
+ attrs['gateway_ip'] = gateway
+ if ('allocation_pools' in parsed_args and
+ 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:
+ if parsed_args.dhcp:
+ attrs['enable_dhcp'] = True
+ elif parsed_args.no_dhcp:
+ attrs['enable_dhcp'] = False
+ if ('dns_nameservers' in parsed_args and
+ parsed_args.dns_nameservers is not None):
attrs['dns_nameservers'] = parsed_args.dns_nameservers
- if parsed_args.host_routes is not None:
+ if 'host_routes' in parsed_args and 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
@@ -163,39 +206,19 @@ class CreateSubnet(command.ShowOne):
'(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',
+ action='store_true',
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',
@@ -208,18 +231,6 @@ class CreateSubnet(command.ShowOne):
"(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,
@@ -246,7 +257,7 @@ class CreateSubnet(command.ShowOne):
metavar='<network>',
help='Network this subnet belongs to (name or ID)',
)
-
+ _get_common_parse_arguments(parser)
return parser
def take_action(self, parsed_args):
@@ -309,6 +320,56 @@ class ListSubnet(command.Lister):
) for s in data))
+class SetSubnet(command.Command):
+ """Set subnet properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(SetSubnet, self).get_parser(prog_name)
+ parser.add_argument(
+ 'subnet',
+ metavar="<subnet>",
+ help=("Subnet to modify (name or ID)")
+ )
+ parser.add_argument(
+ '--name',
+ metavar='<name>',
+ help='Updated name of the subnet',
+ )
+ dhcp_enable_group = parser.add_mutually_exclusive_group()
+ dhcp_enable_group.add_argument(
+ '--dhcp',
+ action='store_true',
+ default=None,
+ help='Enable DHCP',
+ )
+ dhcp_enable_group.add_argument(
+ '--no-dhcp',
+ action='store_true',
+ help='Disable DHCP',
+ )
+ parser.add_argument(
+ '--gateway',
+ metavar='<gateway>',
+ help="Specify a gateway for the subnet. The options are: "
+ " <ip-address>: Specific IP address to use as the gateway "
+ " 'none': This subnet will not use a gateway "
+ "e.g.: --gateway 192.168.9.1, --gateway none"
+ )
+ _get_common_parse_arguments(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_subnet(parsed_args.subnet, ignore_missing=False)
+ attrs = _get_attrs(self.app.client_manager, parsed_args,
+ is_create=False)
+ if not attrs:
+ msg = "Nothing specified to be set"
+ raise exceptions.CommandError(msg)
+ client.update_subnet(obj, **attrs)
+ return
+
+
class ShowSubnet(command.ShowOne):
"""Show subnet details"""
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index d0d8d058..834760fb 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -39,11 +39,11 @@ def _get_attrs(parsed_args):
if parsed_args.prefixes is not None:
attrs['prefixes'] = parsed_args.prefixes
if parsed_args.default_prefix_length is not None:
- attrs['default_prefix_length'] = parsed_args.default_prefix_length
+ attrs['default_prefixlen'] = parsed_args.default_prefix_length
if parsed_args.min_prefix_length is not None:
- attrs['min_prefix_length'] = parsed_args.min_prefix_length
+ attrs['min_prefixlen'] = parsed_args.min_prefix_length
if parsed_args.max_prefix_length is not None:
- attrs['max_prefix_length'] = parsed_args.max_prefix_length
+ attrs['max_prefixlen'] = parsed_args.max_prefix_length
return attrs
diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py
index 2bb0fbfc..860963eb 100644
--- a/openstackclient/tests/compute/v2/fakes.py
+++ b/openstackclient/tests/compute/v2/fakes.py
@@ -425,13 +425,13 @@ class FakeSecurityGroupRule(object):
# Set default attributes.
security_group_rule_attrs = {
- 'from_port': -1,
+ 'from_port': 0,
'group': {},
'id': 'security-group-rule-id-' + uuid.uuid4().hex,
- 'ip_protocol': 'icmp',
+ 'ip_protocol': 'tcp',
'ip_range': {'cidr': '0.0.0.0/0'},
'parent_group_id': 'security-group-id-' + uuid.uuid4().hex,
- 'to_port': -1,
+ 'to_port': 0,
}
# Overwrite default attributes.
diff --git a/openstackclient/tests/compute/v2/test_security_group_rule.py b/openstackclient/tests/compute/v2/test_security_group_rule.py
index 9a8003f3..42bf2c26 100644
--- a/openstackclient/tests/compute/v2/test_security_group_rule.py
+++ b/openstackclient/tests/compute/v2/test_security_group_rule.py
@@ -17,7 +17,6 @@ from openstackclient.compute.v2 import security_group
from openstackclient.tests.compute.v2 import fakes as compute_fakes
from openstackclient.tests import fakes
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
-from openstackclient.tests import utils
security_group_id = '11'
@@ -111,271 +110,6 @@ class TestSecurityGroupRule(compute_fakes.TestComputev2):
self.sg_rules_mock.reset_mock()
-class TestSecurityGroupRuleCreate(TestSecurityGroupRule):
-
- columns = (
- 'id',
- 'ip_protocol',
- 'ip_range',
- 'parent_group_id',
- 'port_range',
- 'remote_security_group',
- )
-
- def setUp(self):
- super(TestSecurityGroupRuleCreate, self).setUp()
-
- self.secgroups_mock.get.return_value = FakeSecurityGroupRuleResource(
- None,
- copy.deepcopy(SECURITY_GROUP),
- loaded=True,
- )
-
- # Get the command object to test
- self.cmd = security_group.CreateSecurityGroupRule(self.app, None)
-
- def test_security_group_rule_create_no_options(self):
- self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource(
- None,
- copy.deepcopy(SECURITY_GROUP_RULE),
- loaded=True,
- )
-
- arglist = [
- security_group_name,
- ]
- verifylist = [
- ('group', security_group_name),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class ShowOne in cliff, abstract method take_action()
- # returns a two-part tuple with a tuple of column names and a tuple of
- # data to be shown.
- columns, data = self.cmd.take_action(parsed_args)
-
- # SecurityGroupManager.create(name, description)
- self.sg_rules_mock.create.assert_called_with(
- security_group_id,
- 'tcp',
- 0,
- 0,
- security_group_rule_cidr,
- None,
- )
-
- self.assertEqual(self.columns, columns)
- datalist = (
- security_group_rule_id,
- 'tcp',
- security_group_rule_cidr,
- security_group_id,
- '0:0',
- '',
- )
- self.assertEqual(datalist, data)
-
- def test_security_group_rule_create_ftp(self):
- sg_rule = copy.deepcopy(SECURITY_GROUP_RULE)
- sg_rule['from_port'] = 20
- sg_rule['to_port'] = 21
- self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource(
- None,
- sg_rule,
- loaded=True,
- )
-
- arglist = [
- security_group_name,
- '--dst-port', '20:21',
- ]
- verifylist = [
- ('group', security_group_name),
- ('dst_port', (20, 21)),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class ShowOne in cliff, abstract method take_action()
- # returns a two-part tuple with a tuple of column names and a tuple of
- # data to be shown.
- columns, data = self.cmd.take_action(parsed_args)
-
- # SecurityGroupManager.create(name, description)
- self.sg_rules_mock.create.assert_called_with(
- security_group_id,
- 'tcp',
- 20,
- 21,
- security_group_rule_cidr,
- None,
- )
-
- self.assertEqual(self.columns, columns)
- datalist = (
- security_group_rule_id,
- 'tcp',
- security_group_rule_cidr,
- security_group_id,
- '20:21',
- '',
- )
- self.assertEqual(datalist, data)
-
- def test_security_group_rule_create_ssh(self):
- sg_rule = copy.deepcopy(SECURITY_GROUP_RULE)
- sg_rule['from_port'] = 22
- sg_rule['to_port'] = 22
- sg_rule['ip_range'] = {}
- sg_rule['group'] = {'name': security_group_name}
- self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource(
- None,
- sg_rule,
- loaded=True,
- )
-
- arglist = [
- security_group_name,
- '--dst-port', '22',
- '--src-group', security_group_id,
- ]
- verifylist = [
- ('group', security_group_name),
- ('dst_port', (22, 22)),
- ('src_group', security_group_id),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class ShowOne in cliff, abstract method take_action()
- # returns a two-part tuple with a tuple of column names and a tuple of
- # data to be shown.
- columns, data = self.cmd.take_action(parsed_args)
-
- # SecurityGroupManager.create(name, description)
- self.sg_rules_mock.create.assert_called_with(
- security_group_id,
- 'tcp',
- 22,
- 22,
- security_group_rule_cidr,
- security_group_id,
- )
-
- self.assertEqual(self.columns, columns)
- datalist = (
- security_group_rule_id,
- 'tcp',
- '',
- security_group_id,
- '22:22',
- security_group_name,
- )
- self.assertEqual(datalist, data)
-
- def test_security_group_rule_create_udp(self):
- sg_rule = copy.deepcopy(SECURITY_GROUP_RULE)
- sg_rule['ip_protocol'] = 'udp'
- self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource(
- None,
- sg_rule,
- loaded=True,
- )
-
- arglist = [
- security_group_name,
- '--proto', 'udp',
- ]
- verifylist = [
- ('group', security_group_name),
- ('proto', 'udp'),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class ShowOne in cliff, abstract method take_action()
- # returns a two-part tuple with a tuple of column names and a tuple of
- # data to be shown.
- columns, data = self.cmd.take_action(parsed_args)
-
- # SecurityGroupManager.create(name, description)
- self.sg_rules_mock.create.assert_called_with(
- security_group_id,
- 'udp',
- 0,
- 0,
- security_group_rule_cidr,
- None,
- )
-
- self.assertEqual(self.columns, columns)
- datalist = (
- security_group_rule_id,
- 'udp',
- security_group_rule_cidr,
- security_group_id,
- '0:0',
- '',
- )
- self.assertEqual(datalist, data)
-
- def test_security_group_rule_create_icmp(self):
- sg_rule_cidr = '10.0.2.0/24'
- sg_rule = copy.deepcopy(SECURITY_GROUP_RULE_ICMP)
- sg_rule['ip_range'] = {'cidr': sg_rule_cidr}
- self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource(
- None,
- sg_rule,
- loaded=True,
- )
-
- arglist = [
- security_group_name,
- '--proto', 'ICMP',
- '--src-ip', sg_rule_cidr,
- ]
- verifylist = [
- ('group', security_group_name),
- ('proto', 'ICMP'),
- ('src_ip', sg_rule_cidr)
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class ShowOne in cliff, abstract method take_action()
- # returns a two-part tuple with a tuple of column names and a tuple of
- # data to be shown.
- columns, data = self.cmd.take_action(parsed_args)
-
- # SecurityGroupManager.create(name, description)
- self.sg_rules_mock.create.assert_called_with(
- security_group_id,
- 'ICMP',
- -1,
- -1,
- sg_rule_cidr,
- None,
- )
-
- self.assertEqual(self.columns, columns)
- datalist = (
- security_group_rule_id,
- 'icmp',
- sg_rule_cidr,
- security_group_id,
- '',
- '',
- )
- self.assertEqual(datalist, data)
-
- def test_security_group_rule_create_src_invalid(self):
- arglist = [
- security_group_name,
- '--proto', 'ICMP',
- '--src-ip', security_group_rule_cidr,
- '--src-group', security_group_id,
- ]
-
- self.assertRaises(utils.ParserException,
- self.check_parser, self.cmd, arglist, [])
-
-
class TestSecurityGroupRuleList(TestSecurityGroupRule):
def setUp(self):
diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py
index 71543274..e35fbe16 100644
--- a/openstackclient/tests/network/v2/fakes.py
+++ b/openstackclient/tests/network/v2/fakes.py
@@ -510,11 +510,11 @@ class FakeSecurityGroupRule(object):
'direction': 'ingress',
'ethertype': 'IPv4',
'id': 'security-group-rule-id-' + uuid.uuid4().hex,
- 'port_range_max': None,
- 'port_range_min': None,
- 'protocol': None,
- 'remote_group_id': 'remote-security-group-id-' + uuid.uuid4().hex,
- 'remote_ip_prefix': None,
+ 'port_range_max': 0,
+ 'port_range_min': 0,
+ 'protocol': 'tcp',
+ 'remote_group_id': None,
+ 'remote_ip_prefix': '0.0.0.0/0',
'security_group_id': 'security-group-id-' + uuid.uuid4().hex,
'tenant_id': 'project-id-' + uuid.uuid4().hex,
}
diff --git a/openstackclient/tests/network/v2/test_floating_ip.py b/openstackclient/tests/network/v2/test_floating_ip.py
index c9da0fa0..3e261fb5 100644
--- a/openstackclient/tests/network/v2/test_floating_ip.py
+++ b/openstackclient/tests/network/v2/test_floating_ip.py
@@ -16,6 +16,7 @@ import mock
from openstackclient.network.v2 import floating_ip
from openstackclient.tests.compute.v2 import fakes as compute_fakes
from openstackclient.tests.network.v2 import fakes as network_fakes
+from openstackclient.tests import utils as tests_utils
# Tests for Neutron network
@@ -29,6 +30,115 @@ class TestFloatingIPNetwork(network_fakes.TestNetworkV2):
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):
# The floating ip to be deleted.
@@ -169,6 +279,62 @@ class TestFloatingIPCompute(compute_fakes.TestComputev2):
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):
# The floating ip to be deleted.
diff --git a/openstackclient/tests/network/v2/test_security_group_rule.py b/openstackclient/tests/network/v2/test_security_group_rule.py
index db15d0e2..81b9e18b 100644
--- a/openstackclient/tests/network/v2/test_security_group_rule.py
+++ b/openstackclient/tests/network/v2/test_security_group_rule.py
@@ -39,6 +39,317 @@ class TestSecurityGroupRuleCompute(compute_fakes.TestComputev2):
self.compute = self.app.client_manager.compute
+class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+
+ # The security group rule to be created.
+ _security_group_rule = None
+
+ # The security group that will contain the rule created.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group()
+
+ expected_columns = (
+ 'direction',
+ 'ethertype',
+ 'id',
+ 'port_range_max',
+ 'port_range_min',
+ 'project_id',
+ 'protocol',
+ 'remote_group_id',
+ 'remote_ip_prefix',
+ 'security_group_id',
+ )
+
+ expected_data = None
+
+ def _setup_security_group_rule(self, attrs=None):
+ self._security_group_rule = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule(
+ attrs)
+ self.network.create_security_group_rule = mock.Mock(
+ return_value=self._security_group_rule)
+ self.expected_data = (
+ self._security_group_rule.direction,
+ self._security_group_rule.ethertype,
+ self._security_group_rule.id,
+ self._security_group_rule.port_range_max,
+ self._security_group_rule.port_range_min,
+ self._security_group_rule.project_id,
+ self._security_group_rule.protocol,
+ self._security_group_rule.remote_group_id,
+ self._security_group_rule.remote_ip_prefix,
+ self._security_group_rule.security_group_id,
+ )
+
+ def setUp(self):
+ super(TestCreateSecurityGroupRuleNetwork, self).setUp()
+
+ self.network.find_security_group = mock.Mock(
+ return_value=self._security_group)
+
+ # Get the command object to test
+ self.cmd = security_group_rule.CreateSecurityGroupRule(
+ self.app, self.namespace)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_source_group_and_ip(self):
+ arglist = [
+ '--src-ip', '10.10.0.0/24',
+ '--src-group', self._security_group.id,
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_bad_protocol(self):
+ arglist = [
+ '--protocol', 'foo',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_default_rule(self):
+ self._setup_security_group_rule({
+ 'port_range_max': 443,
+ 'port_range_min': 443,
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.port_range_min),
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(tuple(self.expected_columns), columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_source_group(self):
+ self._setup_security_group_rule({
+ 'port_range_max': 22,
+ 'port_range_min': 22,
+ 'remote_group_id': self._security_group.id,
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.port_range_min),
+ '--src-group', self._security_group.name,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.port_range_min,
+ self._security_group_rule.port_range_max)),
+ ('src_group', self._security_group.name),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_group_id': self._security_group_rule.remote_group_id,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(tuple(self.expected_columns), columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_source_ip(self):
+ self._setup_security_group_rule({
+ 'protocol': 'icmp',
+ 'port_range_max': -1,
+ 'port_range_min': -1,
+ 'remote_ip_prefix': '10.0.2.0/24',
+ })
+ arglist = [
+ '--proto', self._security_group_rule.protocol,
+ '--src-ip', self._security_group_rule.remote_ip_prefix,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('proto', self._security_group_rule.protocol),
+ ('src_ip', self._security_group_rule.remote_ip_prefix),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(tuple(self.expected_columns), columns)
+ self.assertEqual(self.expected_data, data)
+
+
+class TestCreateSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+
+ # The security group rule to be created.
+ _security_group_rule = None
+
+ # The security group that will contain the rule created.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+
+ def _setup_security_group_rule(self, attrs=None):
+ self._security_group_rule = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule(
+ attrs)
+ self.compute.security_group_rules.create.return_value = \
+ self._security_group_rule
+ expected_columns, expected_data = \
+ security_group_rule._format_security_group_rule_show(
+ self._security_group_rule._info)
+ return expected_columns, expected_data
+
+ def setUp(self):
+ super(TestCreateSecurityGroupRuleCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.get.return_value = self._security_group
+
+ # Get the command object to test
+ self.cmd = security_group_rule.CreateSecurityGroupRule(self.app, None)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_source_group_and_ip(self):
+ arglist = [
+ '--src-ip', '10.10.0.0/24',
+ '--src-group', self._security_group.id,
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_bad_protocol(self):
+ arglist = [
+ '--protocol', 'foo',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_default_rule(self):
+ expected_columns, expected_data = self._setup_security_group_rule()
+ dst_port = str(self._security_group_rule.from_port) + ':' + \
+ str(self._security_group_rule.to_port)
+ arglist = [
+ '--dst-port', dst_port,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.from_port,
+ self._security_group_rule.to_port)),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ None,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ def test_create_source_group(self):
+ expected_columns, expected_data = self._setup_security_group_rule({
+ 'from_port': 22,
+ 'to_port': 22,
+ 'group': {'name': self._security_group.name},
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.from_port),
+ '--src-group', self._security_group.name,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.from_port,
+ self._security_group_rule.to_port)),
+ ('src_group', self._security_group.name),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ self._security_group.id,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ def test_create_source_ip(self):
+ expected_columns, expected_data = self._setup_security_group_rule({
+ 'ip_protocol': 'icmp',
+ 'from_port': -1,
+ 'to_port': -1,
+ 'ip_range': {'cidr': '10.0.2.0/24'},
+ })
+ arglist = [
+ '--proto', self._security_group_rule.ip_protocol,
+ '--src-ip', self._security_group_rule.ip_range['cidr'],
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('proto', self._security_group_rule.ip_protocol),
+ ('src_ip', self._security_group_rule.ip_range['cidr']),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ None,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+
class TestDeleteSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
# The security group rule to be deleted.
@@ -68,7 +379,7 @@ class TestDeleteSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
result = self.cmd.take_action(parsed_args)
- self.network.delete_security_group_rule.assert_called_with(
+ self.network.delete_security_group_rule.assert_called_once_with(
self._security_group_rule)
self.assertIsNone(result)
@@ -98,7 +409,7 @@ class TestDeleteSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
result = self.cmd.take_action(parsed_args)
- self.compute.security_group_rules.delete.assert_called_with(
+ self.compute.security_group_rules.delete.assert_called_once_with(
self._security_group_rule.id)
self.assertIsNone(result)
@@ -160,7 +471,7 @@ class TestShowSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
columns, data = self.cmd.take_action(parsed_args)
- self.network.find_security_group_rule.assert_called_with(
+ self.network.find_security_group_rule.assert_called_once_with(
self._security_group_rule.id, ignore_missing=False)
self.assertEqual(tuple(self.columns), columns)
self.assertEqual(self.data, data)
@@ -207,6 +518,6 @@ class TestShowSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
columns, data = self.cmd.take_action(parsed_args)
- self.compute.security_groups.list.assert_called_with()
+ self.compute.security_groups.list.assert_called_once_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/network/v2/test_subnet.py b/openstackclient/tests/network/v2/test_subnet.py
index de17c789..2535bbe6 100644
--- a/openstackclient/tests/network/v2/test_subnet.py
+++ b/openstackclient/tests/network/v2/test_subnet.py
@@ -14,6 +14,7 @@
import copy
import mock
+from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.network.v2 import subnet as subnet_v2
from openstackclient.tests import fakes
@@ -203,9 +204,9 @@ class TestCreateSubnet(TestSubnet):
self.network.find_network = mock.Mock(return_value=self._network)
arglist = [
- self._subnet.name,
"--subnet-range", self._subnet.cidr,
"--network", self._subnet.network_id,
+ self._subnet.name,
]
verifylist = [
('name', self._subnet.name),
@@ -266,7 +267,7 @@ class TestCreateSubnet(TestSubnet):
('ip_version', self._subnet_from_pool.ip_version),
('gateway', self._subnet_from_pool.gateway_ip),
('dns_nameservers', self._subnet_from_pool.dns_nameservers),
- ('enable_dhcp', self._subnet_from_pool.enable_dhcp),
+ ('dhcp', self._subnet_from_pool.enable_dhcp),
('host_routes', subnet_v2.convert_entries_to_gateway(
self._subnet_from_pool.host_routes)),
('subnet_pool', self._subnet_from_pool.subnetpool_id),
@@ -332,7 +333,7 @@ class TestCreateSubnet(TestSubnet):
('ipv6_address_mode', self._subnet_ipv6.ipv6_address_mode),
('gateway', self._subnet_ipv6.gateway_ip),
('dns_nameservers', self._subnet_ipv6.dns_nameservers),
- ('enable_dhcp', self._subnet_ipv6.enable_dhcp),
+ ('dhcp', self._subnet_ipv6.enable_dhcp),
('host_routes', subnet_v2.convert_entries_to_gateway(
self._subnet_ipv6.host_routes)),
('allocation_pools', self._subnet_ipv6.allocation_pools),
@@ -469,6 +470,73 @@ class TestListSubnet(TestSubnet):
self.assertEqual(self.data_long, list(data))
+class TestSetSubnet(TestSubnet):
+
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+
+ def setUp(self):
+ super(TestSetSubnet, self).setUp()
+ self.network.update_subnet = mock.Mock(return_value=None)
+ self.network.find_subnet = mock.Mock(return_value=self._subnet)
+ self.cmd = subnet_v2.SetSubnet(self.app, self.namespace)
+
+ def test_set_this(self):
+ arglist = [
+ "--name", "new_subnet",
+ "--dhcp",
+ "--gateway", self._subnet.gateway_ip,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', "new_subnet"),
+ ('dhcp', True),
+ ('gateway', self._subnet.gateway_ip),
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'enable_dhcp': True,
+ 'gateway_ip': self._subnet.gateway_ip,
+ 'name': "new_subnet",
+ }
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ "--name", "new_subnet",
+ "--no-dhcp",
+ "--gateway", "none",
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', "new_subnet"),
+ ('no_dhcp', True),
+ ('gateway', "none"),
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'enable_dhcp': False,
+ 'gateway_ip': None,
+ 'name': "new_subnet",
+ }
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_nothing(self):
+ arglist = [self._subnet.name, ]
+ verifylist = [('subnet', self._subnet.name)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+
class TestShowSubnet(TestSubnet):
# The subnets to be shown
_subnet = network_fakes.FakeSubnet.create_one_subnet()
diff --git a/openstackclient/tests/network/v2/test_subnet_pool.py b/openstackclient/tests/network/v2/test_subnet_pool.py
index ebedaf64..6ed2352d 100644
--- a/openstackclient/tests/network/v2/test_subnet_pool.py
+++ b/openstackclient/tests/network/v2/test_subnet_pool.py
@@ -119,9 +119,9 @@ class TestCreateSubnetPool(TestSubnetPool):
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_subnet_pool.assert_called_once_with(**{
- 'default_prefix_length': self._subnet_pool.default_prefixlen,
- 'max_prefix_length': self._subnet_pool.max_prefixlen,
- 'min_prefix_length': self._subnet_pool.min_prefixlen,
+ 'default_prefixlen': self._subnet_pool.default_prefixlen,
+ 'max_prefixlen': self._subnet_pool.max_prefixlen,
+ 'min_prefixlen': self._subnet_pool.min_prefixlen,
'name': self._subnet_pool.name,
})
self.assertEqual(self.columns, columns)
@@ -278,8 +278,8 @@ class TestSetSubnetPool(TestSubnetPool):
attrs = {
'name': 'noob',
- 'default_prefix_length': '8',
- 'min_prefix_length': '8',
+ 'default_prefixlen': '8',
+ 'min_prefixlen': '8',
}
self.network.update_subnet_pool.assert_called_once_with(
self._subnet_pool, **attrs)
@@ -305,7 +305,7 @@ class TestSetSubnetPool(TestSubnetPool):
prefixes.extend(self._subnet_pool.prefixes)
attrs = {
'prefixes': prefixes,
- 'max_prefix_length': '16',
+ 'max_prefixlen': '16',
}
self.network.update_subnet_pool.assert_called_once_with(
self._subnet_pool, **attrs)
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py
index 90827d20..29c197ef 100644
--- a/openstackclient/volume/v1/volume.py
+++ b/openstackclient/volume/v1/volume.py
@@ -31,20 +31,30 @@ class CreateVolume(command.ShowOne):
parser.add_argument(
'name',
metavar='<name>',
- help='New volume name',
+ help='Volume name',
)
parser.add_argument(
'--size',
metavar='<size>',
required=True,
type=int,
- help='New volume size in GB',
+ help='Volume size in GB',
+ )
+ parser.add_argument(
+ '--type',
+ metavar='<volume-type>',
+ help="Set the type of volume",
+ )
+ parser.add_argument(
+ '--image',
+ metavar='<image>',
+ help='Use <image> as source of volume (name or ID)',
)
snapshot_group = parser.add_mutually_exclusive_group()
snapshot_group.add_argument(
'--snapshot',
metavar='<snapshot>',
- help='Use <snapshot> as source of new volume',
+ help='Use <snapshot> as source of volume (name or ID)',
)
snapshot_group.add_argument(
'--snapshot-id',
@@ -52,14 +62,14 @@ class CreateVolume(command.ShowOne):
help=argparse.SUPPRESS,
)
parser.add_argument(
- '--description',
- metavar='<description>',
- help='New volume description',
+ '--source',
+ metavar='<volume>',
+ help='Volume to clone (name or ID)',
)
parser.add_argument(
- '--type',
- metavar='<volume-type>',
- help='Use <volume-type> as the new volume type',
+ '--description',
+ metavar='<description>',
+ help='Volume description',
)
parser.add_argument(
'--user',
@@ -74,17 +84,7 @@ class CreateVolume(command.ShowOne):
parser.add_argument(
'--availability-zone',
metavar='<availability-zone>',
- help='Create new volume in <availability-zone>',
- )
- parser.add_argument(
- '--image',
- metavar='<image>',
- help='Use <image> as source of new volume (name or ID)',
- )
- parser.add_argument(
- '--source',
- metavar='<volume>',
- help='Volume to clone (name or ID)',
+ help='Create volume in <availability-zone>',
)
parser.add_argument(
'--property',
@@ -308,7 +308,7 @@ class SetVolume(command.Command):
parser.add_argument(
'volume',
metavar='<volume>',
- help='Volume to change (name or ID)',
+ help='Volume to modify (name or ID)',
)
parser.add_argument(
'--name',
@@ -330,7 +330,7 @@ class SetVolume(command.Command):
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add or modify for this volume '
+ help='Set a property on this volume '
'(repeat option to set multiple properties)',
)
return parser
@@ -411,7 +411,7 @@ class UnsetVolume(command.Command):
metavar='<key>',
action='append',
default=[],
- help='Property to remove from volume '
+ help='Remove a property from volume '
'(repeat option to remove multiple properties)',
required=True,
)
diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py
index 24d0b235..05671c1f 100644
--- a/openstackclient/volume/v1/volume_type.py
+++ b/openstackclient/volume/v1/volume_type.py
@@ -30,13 +30,13 @@ class CreateVolumeType(command.ShowOne):
parser.add_argument(
'name',
metavar='<name>',
- help='New volume type name',
+ help='Volume type name',
)
parser.add_argument(
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add for this volume type '
+ help='Set a property on this volume type '
'(repeat option to set multiple properties)',
)
return parser
@@ -114,7 +114,7 @@ class SetVolumeType(command.Command):
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add or modify for this volume type '
+ help='Set a property on this volume type '
'(repeat option to set multiple properties)',
)
return parser
@@ -128,6 +128,27 @@ class SetVolumeType(command.Command):
volume_type.set_keys(parsed_args.property)
+class ShowVolumeType(command.ShowOne):
+ """Display volume type details"""
+
+ def get_parser(self, prog_name):
+ parser = super(ShowVolumeType, self).get_parser(prog_name)
+ parser.add_argument(
+ "volume_type",
+ metavar="<volume-type>",
+ help="Volume type to display (name or ID)"
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ volume_type = utils.find_resource(
+ volume_client.volume_types, parsed_args.volume_type)
+ properties = utils.format_dict(volume_type._info.pop('extra_specs'))
+ volume_type._info.update({'properties': properties})
+ return zip(*sorted(six.iteritems(volume_type._info)))
+
+
class UnsetVolumeType(command.Command):
"""Unset volume type properties"""
@@ -143,7 +164,7 @@ class UnsetVolumeType(command.Command):
metavar='<key>',
action='append',
default=[],
- help='Property to remove from volume type '
+ help='Remove a property from this volume type '
'(repeat option to remove multiple properties)',
required=True,
)
@@ -160,24 +181,3 @@ class UnsetVolumeType(command.Command):
volume_type.unset_keys(parsed_args.property)
else:
self.app.log.error("No changes requested\n")
-
-
-class ShowVolumeType(command.ShowOne):
- """Display volume type details"""
-
- def get_parser(self, prog_name):
- parser = super(ShowVolumeType, self).get_parser(prog_name)
- parser.add_argument(
- "volume_type",
- metavar="<volume-type>",
- help="Volume type to display (name or ID)"
- )
- return parser
-
- def take_action(self, parsed_args):
- volume_client = self.app.client_manager.volume
- volume_type = utils.find_resource(
- volume_client.volume_types, parsed_args.volume_type)
- properties = utils.format_dict(volume_type._info.pop('extra_specs'))
- volume_type._info.update({'properties': properties})
- return zip(*sorted(six.iteritems(volume_type._info)))
diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py
index 5d9d2d9e..5b7511e8 100644
--- a/openstackclient/volume/v2/volume.py
+++ b/openstackclient/volume/v2/volume.py
@@ -32,29 +32,39 @@ class CreateVolume(command.ShowOne):
parser.add_argument(
"name",
metavar="<name>",
- help="New volume name"
+ help="Volume name",
)
parser.add_argument(
"--size",
metavar="<size>",
type=int,
required=True,
- help="New volume size in GB"
+ help="Volume size in GB",
+ )
+ parser.add_argument(
+ "--type",
+ metavar="<volume-type>",
+ help="Set the type of volume",
+ )
+ parser.add_argument(
+ "--image",
+ metavar="<image>",
+ help="Use <image> as source of volume (name or ID)",
)
parser.add_argument(
"--snapshot",
metavar="<snapshot>",
- help="Use <snapshot> as source of new volume (name or ID)"
+ help="Use <snapshot> as source of volume (name or ID)",
)
parser.add_argument(
- "--description",
- metavar="<description>",
- help="New volume description"
+ "--source",
+ metavar="<volume>",
+ help="Volume to clone (name or ID)",
)
parser.add_argument(
- "--type",
- metavar="<volume-type>",
- help="Use <volume-type> as the new volume type",
+ "--description",
+ metavar="<description>",
+ help="Volume description",
)
parser.add_argument(
'--user',
@@ -69,24 +79,14 @@ class CreateVolume(command.ShowOne):
parser.add_argument(
"--availability-zone",
metavar="<availability-zone>",
- help="Create new volume in <availability_zone>"
- )
- parser.add_argument(
- "--image",
- metavar="<image>",
- help="Use <image> as source of new volume (name or ID)"
- )
- parser.add_argument(
- "--source",
- metavar="<volume>",
- help="Volume to clone (name or ID)"
+ help="Create volume in <availability-zone>",
)
parser.add_argument(
"--property",
metavar="<key=value>",
action=parseractions.KeyValueAction,
help="Set a property to this volume "
- "(repeat option to set multiple properties)"
+ "(repeat option to set multiple properties)",
)
return parser
@@ -188,13 +188,13 @@ class ListVolume(command.Lister):
parser = super(ListVolume, self).get_parser(prog_name)
parser.add_argument(
'--project',
- metavar='<project-id>',
+ metavar='<project>',
help='Filter results by project (name or ID) (admin only)'
)
identity_common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--user',
- metavar='<user-id>',
+ metavar='<user>',
help='Filter results by user (name or ID) (admin only)'
)
identity_common.add_user_domain_option_to_parser(parser)
@@ -320,7 +320,7 @@ class SetVolume(command.Command):
parser.add_argument(
'volume',
metavar='<volume>',
- help='Volume to change (name or ID)',
+ help='Volume to modify (name or ID)',
)
parser.add_argument(
'--name',
@@ -328,28 +328,28 @@ class SetVolume(command.Command):
help='New volume name',
)
parser.add_argument(
- '--description',
- metavar='<description>',
- help='New volume description',
- )
- parser.add_argument(
'--size',
metavar='<size>',
type=int,
help='Extend volume size in GB',
)
parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help='New volume description',
+ )
+ parser.add_argument(
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add or modify for this volume '
+ help='Set a property on this volume '
'(repeat option to set multiple properties)',
)
parser.add_argument(
'--image-property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='To add or modify image properties for this volume '
+ help='Set an image property on this volume '
'(repeat option to set multiple image properties)',
)
return parser
@@ -434,14 +434,14 @@ class UnsetVolume(command.Command):
'--property',
metavar='<key>',
action='append',
- help='Property to remove from volume '
+ help='Remove a property from volume '
'(repeat option to remove multiple properties)',
)
parser.add_argument(
'--image-property',
metavar='<key>',
action='append',
- help='To remove image properties from volume '
+ help='Remove an image property from volume '
'(repeat option to remove multiple image properties)',
)
return parser
diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py
index d2b3ed6a..5509ac52 100644
--- a/openstackclient/volume/v2/volume_type.py
+++ b/openstackclient/volume/v2/volume_type.py
@@ -29,12 +29,12 @@ class CreateVolumeType(command.ShowOne):
parser.add_argument(
"name",
metavar="<name>",
- help="New volume type name"
+ help="Volume type name",
)
parser.add_argument(
"--description",
metavar="<description>",
- help="New volume type description",
+ help="Volume type description",
)
public_group = parser.add_mutually_exclusive_group()
public_group.add_argument(
@@ -55,7 +55,7 @@ class CreateVolumeType(command.ShowOne):
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add for this volume type'
+ help='Set a property on this volume type'
'(repeat option to set multiple properties)',
)
return parser
@@ -153,7 +153,7 @@ class SetVolumeType(command.Command):
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Property to add or modify for this volume type '
+ help='Set a property on this volume type '
'(repeat option to set multiple properties)',
)
return parser
@@ -221,7 +221,7 @@ class UnsetVolumeType(command.Command):
metavar='<key>',
default=[],
required=True,
- help='Property to remove from volume type '
+ help='Remove a property from this volume type '
'(repeat option to remove multiple properties)',
)
return parser