Merge "cloud: Trivial fixes"
This commit is contained in:
commit
5041ea8687
@ -147,10 +147,8 @@ class BlockStorageCloudMixin:
|
||||
image_obj = self.get_image(image)
|
||||
if not image_obj:
|
||||
raise exceptions.SDKException(
|
||||
"Image {image} was requested as the basis for a new"
|
||||
" volume, but was not found on the cloud".format(
|
||||
image=image
|
||||
)
|
||||
f"Image {image} was requested as the basis for a new "
|
||||
f"volume but was not found on the cloud"
|
||||
)
|
||||
kwargs['imageRef'] = image_obj['id']
|
||||
kwargs = self._get_volume_kwargs(kwargs)
|
||||
|
@ -389,13 +389,14 @@ class ComputeCloudMixin:
|
||||
valid project
|
||||
"""
|
||||
params = {}
|
||||
project_id = None
|
||||
if name_or_id:
|
||||
proj = self.get_project(name_or_id)
|
||||
if not proj:
|
||||
raise exceptions.SDKException("project does not exist")
|
||||
project_id = proj.id
|
||||
params['tenant_id'] = project_id
|
||||
project = self.get_project(name_or_id)
|
||||
if not project:
|
||||
raise exceptions.SDKException(
|
||||
f"Project {name_or_id} was requested but was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
params['tenant_id'] = project.id
|
||||
return self.compute.get_limits(**params).absolute
|
||||
|
||||
def get_keypair(self, name_or_id, filters=None):
|
||||
@ -1048,12 +1049,8 @@ class ComputeCloudMixin:
|
||||
volume = self.get_volume(boot_volume)
|
||||
if not volume:
|
||||
raise exceptions.SDKException(
|
||||
'Volume {boot_volume} is not a valid volume'
|
||||
' in {cloud}:{region}'.format(
|
||||
boot_volume=boot_volume,
|
||||
cloud=self.name,
|
||||
region=self._compute_region,
|
||||
)
|
||||
f"Volume {volume} was requested but was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
block_mapping = {
|
||||
'boot_index': '0',
|
||||
@ -1069,15 +1066,11 @@ class ComputeCloudMixin:
|
||||
image_obj = image
|
||||
else:
|
||||
image_obj = self.get_image(image)
|
||||
if not image_obj:
|
||||
raise exceptions.SDKException(
|
||||
'Image {image} is not a valid image in'
|
||||
' {cloud}:{region}'.format(
|
||||
image=image,
|
||||
cloud=self.name,
|
||||
region=self._compute_region,
|
||||
if not image_obj:
|
||||
raise exceptions.SDKException(
|
||||
f"Image {image} was requested but was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
)
|
||||
|
||||
block_mapping = {
|
||||
'boot_index': '0',
|
||||
@ -1093,23 +1086,19 @@ class ComputeCloudMixin:
|
||||
# If we're attaching volumes on boot but booting from an image,
|
||||
# we need to specify that in the BDM.
|
||||
block_mapping = {
|
||||
u'boot_index': 0,
|
||||
u'delete_on_termination': True,
|
||||
u'destination_type': u'local',
|
||||
u'source_type': u'image',
|
||||
u'uuid': kwargs['imageRef'],
|
||||
'boot_index': 0,
|
||||
'delete_on_termination': True,
|
||||
'destination_type': 'local',
|
||||
'source_type': 'image',
|
||||
'uuid': kwargs['imageRef'],
|
||||
}
|
||||
kwargs['block_device_mapping_v2'].append(block_mapping)
|
||||
for volume in volumes:
|
||||
volume_obj = self.get_volume(volume)
|
||||
if not volume_obj:
|
||||
raise exceptions.SDKException(
|
||||
'Volume {volume} is not a valid volume'
|
||||
' in {cloud}:{region}'.format(
|
||||
volume=volume,
|
||||
cloud=self.name,
|
||||
region=self._compute_region,
|
||||
)
|
||||
f"Volume {volume} was requested but was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
block_mapping = {
|
||||
'boot_index': '-1',
|
||||
@ -1841,7 +1830,8 @@ class ComputeCloudMixin:
|
||||
proj = self.get_project(name_or_id)
|
||||
if not proj:
|
||||
raise exceptions.SDKException(
|
||||
"project does not exist: {name}".format(name=proj.id)
|
||||
f"Project {name_or_id} was requested but was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
|
||||
return self.compute.get_usage(proj, start, end)
|
||||
|
@ -144,8 +144,8 @@ class FloatingIPCloudMixin:
|
||||
else:
|
||||
if filters:
|
||||
raise ValueError(
|
||||
"Nova-network don't support server-side floating ips "
|
||||
"filtering. Use the search_floating_ips method instead"
|
||||
"nova-network doesn't support server-side floating IPs "
|
||||
"filtering. Use the 'search_floating_ips' method instead"
|
||||
)
|
||||
|
||||
floating_ips = self._nova_list_floating_ips()
|
||||
@ -159,7 +159,7 @@ class FloatingIPCloudMixin:
|
||||
neutron. `get_external_ipv4_floating_networks` is what you should
|
||||
almost certainly be using.
|
||||
|
||||
:returns: A list of floating IP pools
|
||||
:returns: A list of floating IP pool objects
|
||||
"""
|
||||
if not self._has_nova_extension('os-floating-ip-pools'):
|
||||
raise exc.OpenStackCloudUnavailableExtension(
|
||||
@ -407,11 +407,11 @@ class FloatingIPCloudMixin:
|
||||
|
||||
if port:
|
||||
raise exceptions.SDKException(
|
||||
"This cloud uses nova-network which does not support"
|
||||
" arbitrary floating-ip/port mappings. Please nudge"
|
||||
" your cloud provider to upgrade the networking stack"
|
||||
" to neutron, or alternately provide the server,"
|
||||
" fixed_address and nat_destination arguments as appropriate"
|
||||
"This cloud uses nova-network which does not support "
|
||||
"arbitrary floating-ip/port mappings. Please nudge "
|
||||
"your cloud provider to upgrade the networking stack "
|
||||
"to neutron, or alternately provide the server, "
|
||||
"fixed_address and nat_destination arguments as appropriate"
|
||||
)
|
||||
# Else, we are using Nova network
|
||||
f_ips = self._normalize_floating_ips(
|
||||
@ -482,8 +482,8 @@ class FloatingIPCloudMixin:
|
||||
break
|
||||
except exceptions.ResourceTimeout:
|
||||
self.log.error(
|
||||
"Timed out on floating ip %(fip)s becoming active."
|
||||
" Deleting",
|
||||
"Timed out on floating ip %(fip)s becoming active. "
|
||||
"Deleting",
|
||||
{'fip': fip_id},
|
||||
)
|
||||
try:
|
||||
@ -499,8 +499,8 @@ class FloatingIPCloudMixin:
|
||||
if fip['port_id'] != port:
|
||||
if server:
|
||||
raise exceptions.SDKException(
|
||||
"Attempted to create FIP on port {port} for server"
|
||||
" {server} but FIP has port {port_id}".format(
|
||||
"Attempted to create FIP on port {port} for server "
|
||||
"{server} but FIP has port {port_id}".format(
|
||||
port=port,
|
||||
port_id=fip['port_id'],
|
||||
server=server['id'],
|
||||
@ -508,8 +508,8 @@ class FloatingIPCloudMixin:
|
||||
)
|
||||
else:
|
||||
raise exceptions.SDKException(
|
||||
"Attempted to create FIP on port {port}"
|
||||
" but something went wrong".format(port=port)
|
||||
"Attempted to create FIP on port {port} "
|
||||
"but something went wrong".format(port=port)
|
||||
)
|
||||
return fip
|
||||
|
||||
@ -542,9 +542,9 @@ class FloatingIPCloudMixin:
|
||||
|
||||
:param floating_ip_id: a floating IP address ID.
|
||||
:param retry: number of times to retry. Optional, defaults to 1,
|
||||
which is in addition to the initial delete call.
|
||||
A value of 0 will also cause no checking of results to
|
||||
occur.
|
||||
which is in addition to the initial delete call.
|
||||
A value of 0 will also cause no checking of results to
|
||||
occur.
|
||||
|
||||
:returns: True if the IP address has been deleted, False if the IP
|
||||
address was not found.
|
||||
@ -566,10 +566,10 @@ class FloatingIPCloudMixin:
|
||||
return True
|
||||
|
||||
raise exceptions.SDKException(
|
||||
"Attempted to delete Floating IP {ip} with ID {id} a total of"
|
||||
" {retry} times. Although the cloud did not indicate any errors"
|
||||
" the floating ip is still in existence. Aborting further"
|
||||
" operations.".format(
|
||||
"Attempted to delete Floating IP {ip} with ID {id} a total of "
|
||||
"{retry} times. Although the cloud did not indicate any errors "
|
||||
"the floating IP is still in existence. Aborting further "
|
||||
"operations.".format(
|
||||
id=floating_ip_id,
|
||||
ip=f_ip['floating_ip_address'],
|
||||
retry=retry + 1,
|
||||
@ -623,9 +623,8 @@ class FloatingIPCloudMixin:
|
||||
IPs by passing in a server to the create_floating_ip call.
|
||||
|
||||
:param retry: number of times to retry. Optional, defaults to 1,
|
||||
which is in addition to the initial delete call.
|
||||
A value of 0 will also cause no checking of results to
|
||||
occur.
|
||||
which is in addition to the initial delete call.
|
||||
A value of 0 will also cause no checking of results to occur.
|
||||
|
||||
:returns: Number of Floating IPs deleted, False if none
|
||||
:raises: :class:`~openstack.exceptions.SDKException` on operation
|
||||
@ -657,15 +656,15 @@ class FloatingIPCloudMixin:
|
||||
:param server: Server dict
|
||||
:param floating_ip: Floating IP dict to attach
|
||||
:param fixed_address: (optional) fixed address to which attach the
|
||||
floating IP to.
|
||||
floating IP to.
|
||||
:param wait: (optional) Wait for the address to appear as assigned
|
||||
to the server. Defaults to False.
|
||||
to the server. Defaults to False.
|
||||
:param timeout: (optional) Seconds to wait, defaults to 60.
|
||||
See the ``wait`` parameter.
|
||||
See the ``wait`` parameter.
|
||||
:param skip_attach: (optional) Skip the actual attach and just do
|
||||
the wait. Defaults to False.
|
||||
the wait. Defaults to False.
|
||||
:param nat_destination: The fixed network the server's port for the
|
||||
FIP to attach to will come from.
|
||||
FIP to attach to will come from.
|
||||
|
||||
:returns: The server ``openstack.compute.v2.server.Server``
|
||||
:raises: :class:`~openstack.exceptions.SDKException` on operation
|
||||
@ -859,11 +858,11 @@ class FloatingIPCloudMixin:
|
||||
:param fixed_address: a fixed address
|
||||
:param reuse: Try to reuse existing ips. Defaults to True.
|
||||
:param wait: (optional) Wait for the address to appear as assigned
|
||||
to the server. Defaults to False.
|
||||
to the server. Defaults to False.
|
||||
:param timeout: (optional) Seconds to wait, defaults to 60.
|
||||
See the ``wait`` parameter.
|
||||
See the ``wait`` parameter.
|
||||
:param nat_destination: (optional) the name of the network of the
|
||||
port to associate with the floating ip.
|
||||
port to associate with the floating ip.
|
||||
|
||||
:returns: the updated server ``openstack.compute.v2.server.Server``
|
||||
"""
|
||||
@ -910,14 +909,13 @@ class FloatingIPCloudMixin:
|
||||
:param server: a server object
|
||||
:param ips: list of floating IP addresses or a single address
|
||||
:param wait: (optional) Wait for the address to appear as assigned
|
||||
to the server. Defaults to False.
|
||||
to the server. Defaults to False.
|
||||
:param timeout: (optional) Seconds to wait, defaults to 60.
|
||||
See the ``wait`` parameter.
|
||||
See the ``wait`` parameter.
|
||||
:param fixed_address: (optional) Fixed address of the server to
|
||||
attach the IP to
|
||||
attach the IP to
|
||||
:param nat_destination: (optional) Name or ID of the network that
|
||||
the fixed IP to attach the
|
||||
floating IP should be on
|
||||
the fixed IP to attach the floating IP should be on
|
||||
|
||||
:returns: The updated server ``openstack.compute.v2.server.Server``
|
||||
:raises: :class:`~openstack.exceptions.SDKException` on operation
|
||||
@ -953,15 +951,14 @@ class FloatingIPCloudMixin:
|
||||
|
||||
:param server: a server dictionary.
|
||||
:param reuse: Whether or not to attempt to reuse IPs, defaults
|
||||
to True.
|
||||
to True.
|
||||
:param wait: (optional) Wait for the address to appear as assigned
|
||||
to the server. Defaults to False.
|
||||
to the server. Defaults to False.
|
||||
:param timeout: (optional) Seconds to wait, defaults to 60.
|
||||
See the ``wait`` parameter.
|
||||
See the ``wait`` parameter.
|
||||
:param reuse: Try to reuse existing ips. Defaults to True.
|
||||
|
||||
:returns: Floating IP address attached to server.
|
||||
|
||||
"""
|
||||
server = self._add_auto_ip(
|
||||
server, wait=wait, timeout=timeout, reuse=reuse
|
||||
@ -1004,10 +1001,10 @@ class FloatingIPCloudMixin:
|
||||
# It failed. Delete so as not to leak an unmanaged
|
||||
# resource
|
||||
self.log.error(
|
||||
"Timeout waiting for floating IP to become"
|
||||
" active. Floating IP %(ip)s:%(id)s was created for"
|
||||
" server %(server)s but is being deleted due to"
|
||||
" activation failure.",
|
||||
"Timeout waiting for floating IP to become "
|
||||
"active. Floating IP %(ip)s:%(id)s was created for "
|
||||
"server %(server)s but is being deleted due to "
|
||||
"activation failure.",
|
||||
{
|
||||
'ip': f_ip['floating_ip_address'],
|
||||
'id': f_ip['id'],
|
||||
@ -1265,7 +1262,7 @@ class FloatingIPCloudMixin:
|
||||
Neutron.
|
||||
This function extract attributes that are common to Nova and Neutron
|
||||
floating IP resource.
|
||||
If the whole structure is needed inside shade, shade provides private
|
||||
If the whole structure is needed inside openstacksdk there are private
|
||||
methods that returns "original" objects (e.g.
|
||||
_neutron_allocate_floating_ip)
|
||||
|
||||
|
@ -652,8 +652,10 @@ class NetworkCloudMixin:
|
||||
|
||||
proj = self.get_project(name_or_id)
|
||||
if not proj:
|
||||
raise exceptions.SDKException("project does not exist")
|
||||
|
||||
raise exceptions.SDKException(
|
||||
f"Project {name_or_id} was requested by was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
self.network.update_quota(proj.id, **kwargs)
|
||||
|
||||
def get_network_quotas(self, name_or_id, details=False):
|
||||
@ -688,7 +690,10 @@ class NetworkCloudMixin:
|
||||
"""
|
||||
proj = self.get_project(name_or_id)
|
||||
if not proj:
|
||||
raise exceptions.SDKException("project does not exist")
|
||||
raise exceptions.SDKException(
|
||||
f"Project {name_or_id} was requested by was not found "
|
||||
f"on the cloud"
|
||||
)
|
||||
self.network.delete_quota(proj.id)
|
||||
|
||||
@_utils.valid_kwargs(
|
||||
|
@ -146,12 +146,12 @@ class NetworkCommonCloudMixin:
|
||||
if self._nat_source in (network['name'], network['id']):
|
||||
if nat_source:
|
||||
raise exceptions.SDKException(
|
||||
'Multiple networks were found matching'
|
||||
' {nat_net} which is the network configured'
|
||||
' to be the NAT source. Please check your'
|
||||
' cloud resources. It is probably a good idea'
|
||||
' to configure this network by ID rather than'
|
||||
' by name.'.format(nat_net=self._nat_source)
|
||||
'Multiple networks were found matching '
|
||||
'{nat_net} which is the network configured '
|
||||
'to be the NAT source. Please check your '
|
||||
'cloud resources. It is probably a good idea '
|
||||
'to configure this network by ID rather than '
|
||||
'by name.'.format(nat_net=self._nat_source)
|
||||
)
|
||||
external_ipv4_floating_networks.append(network)
|
||||
nat_source = network
|
||||
@ -164,12 +164,12 @@ class NetworkCommonCloudMixin:
|
||||
if self._nat_destination in (network['name'], network['id']):
|
||||
if nat_destination:
|
||||
raise exceptions.SDKException(
|
||||
'Multiple networks were found matching'
|
||||
' {nat_net} which is the network configured'
|
||||
' to be the NAT destination. Please check your'
|
||||
' cloud resources. It is probably a good idea'
|
||||
' to configure this network by ID rather than'
|
||||
' by name.'.format(nat_net=self._nat_destination)
|
||||
'Multiple networks were found matching '
|
||||
'{nat_net} which is the network configured '
|
||||
'to be the NAT destination. Please check your '
|
||||
'cloud resources. It is probably a good idea '
|
||||
'to configure this network by ID rather than '
|
||||
'by name.'.format(nat_net=self._nat_destination)
|
||||
)
|
||||
nat_destination = network
|
||||
elif self._nat_destination is None:
|
||||
@ -199,13 +199,13 @@ class NetworkCommonCloudMixin:
|
||||
if self._default_network in (network['name'], network['id']):
|
||||
if default_network:
|
||||
raise exceptions.SDKException(
|
||||
'Multiple networks were found matching'
|
||||
' {default_net} which is the network'
|
||||
' configured to be the default interface'
|
||||
' network. Please check your cloud resources.'
|
||||
' It is probably a good idea'
|
||||
' to configure this network by ID rather than'
|
||||
' by name.'.format(default_net=self._default_network)
|
||||
'Multiple networks were found matching '
|
||||
'{default_net} which is the network '
|
||||
'configured to be the default interface '
|
||||
'network. Please check your cloud resources. '
|
||||
'It is probably a good idea '
|
||||
'to configure this network by ID rather than '
|
||||
'by name.'.format(default_net=self._default_network)
|
||||
)
|
||||
default_network = network
|
||||
|
||||
@ -213,8 +213,8 @@ class NetworkCommonCloudMixin:
|
||||
for net_name in self._external_ipv4_names:
|
||||
if net_name not in [net['name'] for net in external_ipv4_networks]:
|
||||
raise exceptions.SDKException(
|
||||
"Networks: {network} was provided for external IPv4"
|
||||
" access and those networks could not be found".format(
|
||||
"Networks: {network} was provided for external IPv4 "
|
||||
"access and those networks could not be found".format(
|
||||
network=net_name
|
||||
)
|
||||
)
|
||||
@ -222,8 +222,8 @@ class NetworkCommonCloudMixin:
|
||||
for net_name in self._internal_ipv4_names:
|
||||
if net_name not in [net['name'] for net in internal_ipv4_networks]:
|
||||
raise exceptions.SDKException(
|
||||
"Networks: {network} was provided for internal IPv4"
|
||||
" access and those networks could not be found".format(
|
||||
"Networks: {network} was provided for internal IPv4 "
|
||||
"access and those networks could not be found".format(
|
||||
network=net_name
|
||||
)
|
||||
)
|
||||
@ -231,8 +231,8 @@ class NetworkCommonCloudMixin:
|
||||
for net_name in self._external_ipv6_names:
|
||||
if net_name not in [net['name'] for net in external_ipv6_networks]:
|
||||
raise exceptions.SDKException(
|
||||
"Networks: {network} was provided for external IPv6"
|
||||
" access and those networks could not be found".format(
|
||||
"Networks: {network} was provided for external IPv6 "
|
||||
"access and those networks could not be found".format(
|
||||
network=net_name
|
||||
)
|
||||
)
|
||||
@ -240,31 +240,31 @@ class NetworkCommonCloudMixin:
|
||||
for net_name in self._internal_ipv6_names:
|
||||
if net_name not in [net['name'] for net in internal_ipv6_networks]:
|
||||
raise exceptions.SDKException(
|
||||
"Networks: {network} was provided for internal IPv6"
|
||||
" access and those networks could not be found".format(
|
||||
"Networks: {network} was provided for internal IPv6 "
|
||||
"access and those networks could not be found".format(
|
||||
network=net_name
|
||||
)
|
||||
)
|
||||
|
||||
if self._nat_destination and not nat_destination:
|
||||
raise exceptions.SDKException(
|
||||
'Network {network} was configured to be the'
|
||||
' destination for inbound NAT but it could not be'
|
||||
' found'.format(network=self._nat_destination)
|
||||
'Network {network} was configured to be the '
|
||||
'destination for inbound NAT but it could not be '
|
||||
'found'.format(network=self._nat_destination)
|
||||
)
|
||||
|
||||
if self._nat_source and not nat_source:
|
||||
raise exceptions.SDKException(
|
||||
'Network {network} was configured to be the'
|
||||
' source for inbound NAT but it could not be'
|
||||
' found'.format(network=self._nat_source)
|
||||
'Network {network} was configured to be the '
|
||||
'source for inbound NAT but it could not be '
|
||||
'found'.format(network=self._nat_source)
|
||||
)
|
||||
|
||||
if self._default_network and not default_network:
|
||||
raise exceptions.SDKException(
|
||||
'Network {network} was configured to be the'
|
||||
' default network interface but it could not be'
|
||||
' found'.format(network=self._default_network)
|
||||
'Network {network} was configured to be the '
|
||||
'default network interface but it could not be '
|
||||
'found'.format(network=self._default_network)
|
||||
)
|
||||
|
||||
self._external_ipv4_networks = external_ipv4_networks
|
||||
|
@ -54,15 +54,14 @@ class SecurityGroupCloudMixin:
|
||||
# pass filters dict to the list to filter as much as possible on
|
||||
# the server side
|
||||
return list(self.network.security_groups(**filters))
|
||||
|
||||
# Handle nova security groups
|
||||
else:
|
||||
data = proxy._json_response(
|
||||
self.compute.get('/os-security-groups', params=filters)
|
||||
)
|
||||
return self._normalize_secgroups(
|
||||
self._get_and_munchify('security_groups', data)
|
||||
)
|
||||
return self._normalize_secgroups(
|
||||
self._get_and_munchify('security_groups', data)
|
||||
)
|
||||
|
||||
def get_security_group(self, name_or_id, filters=None):
|
||||
"""Get a security group by name or ID.
|
||||
@ -109,9 +108,9 @@ class SecurityGroupCloudMixin:
|
||||
self.compute.get(f'/os-security-groups/{id}'),
|
||||
error_message=error_message,
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
|
||||
def create_security_group(
|
||||
self, name, description, project_id=None, stateful=None
|
||||
@ -155,9 +154,9 @@ class SecurityGroupCloudMixin:
|
||||
json={'security_group': security_group_json},
|
||||
)
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
|
||||
def delete_security_group(self, name_or_id):
|
||||
"""Delete a security group
|
||||
@ -237,9 +236,9 @@ class SecurityGroupCloudMixin:
|
||||
json={'security_group': kwargs},
|
||||
)
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
return self._normalize_secgroup(
|
||||
self._get_and_munchify('security_group', data)
|
||||
)
|
||||
|
||||
def create_security_group_rule(
|
||||
self,
|
||||
@ -389,9 +388,9 @@ class SecurityGroupCloudMixin:
|
||||
'/os-security-group-rules', json=security_group_rule_dict
|
||||
)
|
||||
)
|
||||
return self._normalize_secgroup_rule(
|
||||
self._get_and_munchify('security_group_rule', data)
|
||||
)
|
||||
return self._normalize_secgroup_rule(
|
||||
self._get_and_munchify('security_group_rule', data)
|
||||
)
|
||||
|
||||
def delete_security_group_rule(self, rule_id):
|
||||
"""Delete a security group rule
|
||||
|
@ -110,7 +110,8 @@ class TestFloatingIP(base.TestCase):
|
||||
def test_list_floating_ips_with_filters(self):
|
||||
self.assertRaisesRegex(
|
||||
ValueError,
|
||||
"Nova-network don't support server-side",
|
||||
"nova-network doesn't support server-side floating IPs filtering. "
|
||||
"Use the 'search_floating_ips' method instead",
|
||||
self.cloud.list_floating_ips,
|
||||
filters={'Foo': 42},
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user