Subnets and Ports behaviors client and cleanUp methods with retries and timeouts

- Adding subnets and ports behaviors methods with retries and response checks for update, get, list and delete api client calls
- Adding subnets and ports behaviors delete clean up methods based on delete timeouts, intended for tearDown and cleanUP test methods

Change-Id: I50e3fc678c46d8b6c4bf6afda0e43af020c9ce7c
This commit is contained in:
Leonardo Maycotte 2014-09-19 08:48:52 -05:00
parent 71fbeb4742
commit cd47e56366
6 changed files with 690 additions and 52 deletions

View File

@ -168,3 +168,7 @@ class NetworkingResponse(object):
def __init__(self):
self.response = None
self.failures = list()
def __repr__(self):
return 'response: {0}\nfailures: {1}'.format(self.response,
self.failures)

View File

@ -46,12 +46,12 @@ class NetworkingBaseConfig(ConfigSectionInterface):
@property
def resource_create_timeout(self):
"""Seconds to wait for creating a resource"""
return int(self.get("resource_create_timeout", 10))
return int(self.get("resource_create_timeout", 7))
@property
def resource_delete_timeout(self):
"""Seconds to wait for deleting a resource"""
return int(self.get("resource_delete_timeout", 10))
return int(self.get("resource_delete_timeout", 7))
@property
def resource_change_status_timeout(self):

View File

@ -45,12 +45,12 @@ class NetworkingEndpointConfig(ConfigSectionInterface):
@property
def networking_endpoint_url(self):
"""Optional override of the Networking url"""
return self.get("networking_endpoint_url")
return self.get("networking_endpoint_url", '')
@property
def header_tenant_id(self):
"""Optional tenant ID to set in client request headers"""
return self.get("header_tenant_id")
return self.get("header_tenant_id", '')
class NetworkingAdminEndpointConfig(NetworkingEndpointConfig):

View File

@ -59,9 +59,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@type use_exact_name: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Network entity and the failure list if created successful, or
None and the failure list if the raise_exception flag was False
@rtype: tuple with Network or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
if name is None:
name = rand_name(self.config.starts_with_name)
@ -86,11 +85,12 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.CREATE_NETWORK, label=name,
message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the create was successful the
# first time
if not resp_check:
result.response = resp
return result
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -130,9 +130,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Network entity and the failure list if updated successful, or
None and the failure list if the raise_exception flag was False
@rtype: tuple with Network or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_update_attempts = (resource_update_attempts or
@ -153,11 +152,12 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.UPDATE_NETWORK,
label=network_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the update was successful the
# first time
if not resp_check:
result.response = resp
return result
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -184,9 +184,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Network entity and the failure list if the get successful, or
None and the failure list if the raise_exception flag was False
@rtype: tuple with Network or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_get_attempts = (resource_get_attempts or
@ -204,11 +203,12 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.GET_NETWORK,
label=network_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the get was successful the
# first time
if not resp_check:
result.response = resp
return result
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -254,9 +254,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Network entity and the failure list if the list was successful
or None and the failure list if the raise_exception flag was False
@rtype: tuple with Network list or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_list_attempts = (resource_list_attempts or
@ -278,11 +277,12 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.LIST_NETWORKS,
label='', message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the list was successful the
# first time
if not resp_check:
result.response = resp
return result
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -308,9 +308,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: True and the failure list if the delete was successful
or None and the failure list if the raise_exception flag was False
@rtype: tuple with True or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_delete_attempts = (resource_delete_attempts or
@ -322,11 +321,11 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
attempt + 1, resource_delete_attempts, network_id))
resp = self.client.delete_network(network_id=network_id)
result.response = resp
# Delete response is without entity so resp_check can not be used
if (resp.ok and
resp.status_code == NeutronResponseCodes.DELETE_NETWORK):
result.response = True
return result
err_msg = ('{network} Network Delete failure, expected status '
@ -372,14 +371,15 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
try:
self.client.delete_network(network_id=network_id)
resp = self.client.get_network(network_id=network_id)
if resp.status_code == NeutronResponseCodes.NOT_FOUND:
return None
except Exception as err:
err_msg = ('Encountered an exception deleting a network with'
'the clean_network method. Exception: {0}').format(err)
self._log.error(err_msg)
finally:
time.sleep(poll_interval)
if resp.status_code == NeutronResponseCodes.NOT_FOUND:
return None
time.sleep(poll_interval)
err_msg = 'Unable to delete {0} network within a {1}s timeout'.format(
network_id, timeout)
self._log.error(err_msg)
@ -388,9 +388,9 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
def clean_networks(self, networks_list):
"""
@summary: deletes each network from a list calling clean_network
@param network_list: list of network UUIDs
@type network_list: list(str)
@return: list of undeleted network UUIDs
@param networks_list: list of network UUIDs
@type networks_list: list(str)
@return: list of undeleted networks UUIDs
@rtype: list(str)
"""
log_msg = 'Deleting networks: {0}'.format(networks_list)

View File

@ -15,13 +15,17 @@ limitations under the License.
"""
import time
import time
from cloudcafe.common.tools.datagen import rand_name
from cloudcafe.networking.networks.common.behaviors \
import NetworkingBaseBehaviors, NetworkingResponse
from cloudcafe.networking.networks.common.constants \
import NeutronResponseCodes
from cloudcafe.networking.networks.common.exceptions \
import ResourceBuildException, NetworkIDMissingException
import NetworkIDMissingException, ResourceBuildException,\
ResourceDeleteException, ResourceGetException, ResourceListException,\
ResourceUpdateException
class PortsBehaviors(NetworkingBaseBehaviors):
@ -72,9 +76,8 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@type use_exact_name: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Port entity if created successful and the failure list, or
None and the failure list if the raise_exception flag was False
@rtype: tuple with Port or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
if not network_id:
raise NetworkIDMissingException
@ -105,11 +108,12 @@ class PortsBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.CREATE_PORT, label=name,
message=err_msg, network_id=network_id)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the create was successful the
# first time
if not resp_check:
result.response = resp
return result
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -121,3 +125,317 @@ class PortsBehaviors(NetworkingBaseBehaviors):
if raise_exception:
raise ResourceBuildException(err_msg)
return result
def update_port(self, port_id, name=None, admin_state_up=None,
fixed_ips=None, device_id=None, device_owner=None,
security_groups=None, resource_update_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Updates and verifies a specified Port
@param port_id: The UUID for the port
@type port_id: string
@param name: human readable name for the port, may not be unique
(CRUD: CRU)
@type name: string
@param admin_state_up: true or false (default true), the admin state
of the port. If down, the port does not forward packets (CRUD: CRU)
@type admin_state_up: bool
@param fixed_ips: ip addresses for the port associating the port with
the subnets where the IPs come from (CRUD: CRU)
@type fixed_ips: list(dict)
@param device_id: id of device using this port (CRUD: CRUD)
@type device_id: string
@param string device_owner: entity using this port (ex. dhcp agent,
CRUD: CRUD)
@type device_owner: string
@param security_groups: ids of any security groups associated with the
port (CRUD: CRUD)
@type security_groups: list(dict)
@param resource_update_attempts: number of API retries
@type resource_update_attempts: int
@param raise_exception: flag to raise an exception if the
Port was not updated or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_update_attempts = (resource_update_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Port Update failure'
for attempt in range(resource_update_attempts):
self._log.debug('Attempt {0} of {1} updating port {2}'.format(
attempt + 1, resource_update_attempts, port_id))
resp = self.client.update_port(
port_id=port_id, name=name, admin_state_up=admin_state_up,
fixed_ips=fixed_ips, device_id=device_id,
device_owner=device_owner, security_groups=security_groups)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.UPDATE_PORT,
label=port_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the update was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to update {0} port after {1} attempts: '
'{2}').format(port_id, resource_update_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceUpdateException(err_msg)
return result
def get_port(self, port_id, resource_get_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Shows and verifies a specified port
@param port_id: The UUID for the port
@type port_id: string
@param resource_get_attempts: number of API retries
@type resource_get_attempts: int
@param raise_exception: flag to raise an exception if the get
Port was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_get_attempts = (resource_get_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Port Get failure'
for attempt in range(resource_get_attempts):
self._log.debug('Attempt {0} of {1} getting network {2}'.format(
attempt + 1, resource_get_attempts, port_id))
resp = self.client.get_port(port_id=port_id)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.GET_PORT,
label=port_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the get was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to GET {0} port after {1} attempts: '
'{2}').format(port_id, resource_get_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceGetException(err_msg)
return result
def list_ports(self, port_id=None, network_id=None, name=None, status=None,
admin_state_up=None, device_id=None, tenant_id=None,
device_owner=None, mac_address=None, limit=None,
marker=None, page_reverse=None, resource_list_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Lists ports and verifies the response is the expected
@param port_id: The UUID for the port to filter by
@type port_id: string
@param network_id: network ID to filter by
@type network_id: string
@param name: port name to filter by
@type name: string
@param status: port status to filter by
@type status: string
@param admin_state_up: Admin state of the port to filter by
@type admin_state_up: bool
@param device_id: id of device to filter by
@type device_id: string
@param tenant_id: owner of the port to filter by
@type tenant_id: string
@param device_owner: device owner to filter by
@type device_owner: string
@param mac_address: mac address to filter by
@type mac_address: string
@param limit: page size
@type limit: int
@param marker: Id of the last item of the previous page
@type marker: string
@param page_reverse: direction of the page
@type page_reverse: bool
@param resource_list_attempts: number of API retries
@type resource_list_attempts: int
@param raise_exception: flag to raise an exception if the list
Port was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_list_attempts = (resource_list_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Port List failure'
for attempt in range(resource_list_attempts):
self._log.debug('Attempt {0} of {1} with port list'.format(
attempt + 1, resource_list_attempts))
resp = self.client.list_ports(
port_id=port_id, network_id=network_id, name=name,
status=status, admin_state_up=admin_state_up,
device_id=device_id, tenant_id=tenant_id,
device_owner=device_owner, mac_address=mac_address,
limit=limit, marker=marker, page_reverse=page_reverse)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.LIST_PORTS,
label='', message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the list was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to LIST ports after {0} attempts: '
'{1}').format(resource_list_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceListException(err_msg)
return result
def delete_port(self, port_id, resource_delete_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Deletes and verifies a specified port is deleted
@param string port_id: The UUID for the port
@type port_id: string
@param resource_delete_attempts: number of API retries
@type resource_delete_attempts: int
@param raise_exception: flag to raise an exception if the deleted
Port was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_delete_attempts = (resource_delete_attempts or
self.config.api_retries)
result = NetworkingResponse()
for attempt in range(resource_delete_attempts):
self._log.debug('Attempt {0} of {1} deleting port {2}'.format(
attempt + 1, resource_delete_attempts, port_id))
resp = self.client.delete_port(port_id=port_id)
result.response = resp
# Delete response is without entity so resp_check can not be used
if (resp.ok and
resp.status_code == NeutronResponseCodes.DELETE_PORT):
return result
err_msg = ('{port} Port Delete failure, expected status '
'code: {expected_status}. Response: {status} {reason} '
'{content}').format(
port=port_id,
expected_status=NeutronResponseCodes.DELETE_PORT,
status=resp.status_code, reason=resp.reason,
content=resp.content)
self._log.error(err_msg)
result.failures.append(err_msg)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to DELETE {0} port after {1} attempts: '
'{2}').format(port_id, resource_delete_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceDeleteException(err_msg)
return result
def clean_port(self, port_id, timeout=None, poll_interval=None):
"""
@summary: deletes a port within a time out
@param string port_id: The UUID for the port
@type port_id: string
@param timeout: seconds to wait for the port to be deleted
@type timeout: int
@param poll_interval: sleep time interval between API delete/get calls
@type poll_interval: int
@return: None if delete was successful or the undeleted port_id
@rtype: None or string
"""
timeout = timeout or self.config.resource_delete_timeout
poll_interval = poll_interval or self.config.api_poll_interval
endtime = time.time() + int(timeout)
log_msg = 'Deleting {0} port within a {1}s timeout '.format(
port_id, timeout)
self._log.info(log_msg)
while time.time() < endtime:
try:
self.client.delete_port(port_id=port_id)
resp = self.client.get_port(port_id=port_id)
except Exception as err:
err_msg = ('Encountered an exception deleting a port with'
'the clean_network method. Exception: {0}').format(err)
self._log.error(err_msg)
if resp.status_code == NeutronResponseCodes.NOT_FOUND:
return None
time.sleep(poll_interval)
err_msg = 'Unable to delete {0} port within a {1}s timeout'.format(
port_id, timeout)
self._log.error(err_msg)
return port_id
def clean_ports(self, ports_list):
"""
@summary: deletes each port from a list calling clean_port
@param ports_list: list of ports UUIDs
@type ports_list: list(str)
@return: list of undeleted ports UUIDs
@rtype: list(str)
"""
log_msg = 'Deleting ports: {0}'.format(ports_list)
self._log.info(log_msg)
undeleted_ports = []
for port in ports_list:
result = self.clean_port(port_id=port)
if result:
undeleted_ports.append(result)
if undeleted_ports:
err_msg = 'Unable to delete ports: {0}'.format(
undeleted_ports)
self._log.error(err_msg)
return undeleted_ports

View File

@ -24,8 +24,9 @@ from cloudcafe.networking.networks.common.behaviors \
from cloudcafe.networking.networks.common.constants \
import NeutronResponseCodes
from cloudcafe.networking.networks.common.exceptions \
import ResourceBuildException, NetworkIDMissingException, \
InvalidIPException
import InvalidIPException, NetworkIDMissingException,\
ResourceBuildException, ResourceDeleteException, ResourceGetException,\
ResourceListException, ResourceUpdateException
class SubnetsBehaviors(NetworkingBaseBehaviors):
@ -240,9 +241,8 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@type use_exact_name: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: Subnet entity and failure list if created successful, or
None and the failure list if the raise_exception flag was False
@rtype: tuple with Subnet or None and failure list (may be empty)
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
if not network_id:
raise NetworkIDMissingException
@ -286,9 +286,12 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
status_code=NeutronResponseCodes.CREATE_SUBNET, label=name,
message=err_msg, network_id=network_id)
result.response = resp
if not resp_check:
result.response = resp
return result
# Failures will be an empty list if the update was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
@ -300,3 +303,316 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
if raise_exception:
raise ResourceBuildException(err_msg)
return result
def update_subnet(self, subnet_id, name=None, gateway_ip=None,
dns_nameservers=None, host_routes=None,
enable_dhcp=None, allocation_pools=None,
resource_update_attempts=None, raise_exception=False,
poll_interval=None):
"""
@summary: Updates and verifies a specified Subnet
@param subnet_id: The UUID for the subnet
@type subnet_id: string
@param name: human readable name for the subnet, may not be unique
(CRUD: CRU)
@type name: string
@param gateway_ip: default gateway used by devices in the subnet
(CRUD: CRUD)
@type gateway_ip: string
@param dns_nameservers: DNS name servers used by subnet hosts
(CRUD: CRU)
@type dns_nameservers: list(str)
@param host_routes: routes that should be used by devices with IPs
from this subnet (does not includes the local route (CRUD: CRU)
@type host_routes: list(dict)
@param enable_dhcp: whether DHCP is enabled (CRUD:CRU)
@type enable_dhcp: bool
@param allocation_pools: sub range of cidr available for dynamic
allocation to ports (CRUD: CRU)
@type allocation_pools: list(dict)
@param resource_update_attempts: number of API retries
@type resource_update_attempts: int
@param raise_exception: flag to raise an exception if the
Subnet was not updated or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_update_attempts = (resource_update_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Subnet Update failure'
for attempt in range(resource_update_attempts):
self._log.debug('Attempt {0} of {1} updating subnet {2}'.format(
attempt + 1, resource_update_attempts, subnet_id))
resp = self.client.update_subnet(
subnet_id=subnet_id, name=name, gateway_ip=gateway_ip,
dns_nameservers=dns_nameservers, host_routes=host_routes,
enable_dhcp=enable_dhcp, allocation_pools=allocation_pools)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.UPDATE_SUBNET,
label=subnet_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the update was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to update {0} subnet after {1} attempts: '
'{2}').format(subnet_id, resource_update_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceUpdateException(err_msg)
return result
def get_subnet(self, subnet_id, resource_get_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Shows and verifies a specified subnet
@param subnet_id: The UUID for the subnet
@type subnet_id: string
@param resource_get_attempts: number of API retries
@type resource_get_attempts: int
@param raise_exception: flag to raise an exception if the get
Subnet was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_get_attempts = (resource_get_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Subnet Get failure'
for attempt in range(resource_get_attempts):
self._log.debug('Attempt {0} of {1} getting subnet {2}'.format(
attempt + 1, resource_get_attempts, subnet_id))
resp = self.client.get_subnet(subnet_id=subnet_id)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.GET_SUBNET,
label=subnet_id, message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the get was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to GET {0} subnet after {1} attempts: '
'{2}').format(subnet_id, resource_get_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceGetException(err_msg)
return result
def list_subnets(self, subnet_id=None, network_id=None, cidr=None,
tenant_id=None, gateway_ip=None, ip_version=None,
enable_dhcp=None, name=None, limit=None, marker=None,
page_reverse=None, resource_list_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Lists subnets and verifies the response is the expected
@param subnet_id: subnet ID to filter by
@type subnet_id: string
@param network_id: network ID to filter by
@type network_id: string
@param cidr: cider to filter by
@type cidr: string
@param tenant_id: owner of the network to filter by
@type tenant_id: string
@param gateway_ip: gateway_ip to filter by
@type gateway_ip: string
@param ip_version: IP version 4 or 6 to filter by
@type ip_version: int
@param enable_dhcp: enable_dhcp status to filter by
@type enable_dhcp: bool
@param name: subnet name to filter by
@type name: string
@param limit: page size
@type limit: int
@param marker: Id of the last item of the previous page
@type marker: string
@param page_reverse: direction of the page
@type page_reverse: bool
@param resource_list_attempts: number of API retries
@type resource_list_attempts: int
@param raise_exception: flag to raise an exception if the list
Subnet was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_list_attempts = (resource_list_attempts or
self.config.api_retries)
result = NetworkingResponse()
err_msg = 'Subnet List failure'
for attempt in range(resource_list_attempts):
self._log.debug('Attempt {0} of {1} with subnet list'.format(
attempt + 1, resource_list_attempts))
resp = self.client.list_subnets(
subnet_id=subnet_id, network_id=network_id, cidr=cidr,
tenant_id=tenant_id, gateway_ip=gateway_ip,
ip_version=ip_version, enable_dhcp=enable_dhcp, name=name,
limit=limit, marker=marker, page_reverse=page_reverse)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.LIST_SUBNETS,
label='', message=err_msg)
result.response = resp
if not resp_check:
return result
# Failures will be an empty list if the list was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to LIST subnets after {0} attempts: '
'{1}').format(resource_list_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceListException(err_msg)
return result
def delete_subnet(self, subnet_id, resource_delete_attempts=None,
raise_exception=False, poll_interval=None):
"""
@summary: Deletes and verifies a specified subnet is deleted
@param subnet_id: The UUID for the subnet
@type subnet_id: string
@param resource_delete_attempts: number of API retries
@type resource_delete_attempts: int
@param raise_exception: flag to raise an exception if the deleted
Subnet was not as expected or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
poll_interval = poll_interval or self.config.api_poll_interval
resource_delete_attempts = (resource_delete_attempts or
self.config.api_retries)
result = NetworkingResponse()
for attempt in range(resource_delete_attempts):
self._log.debug('Attempt {0} of {1} deleting subnet {2}'.format(
attempt + 1, resource_delete_attempts, subnet_id))
resp = self.client.delete_subnet(subnet_id=subnet_id)
result.response = resp
# Delete response is without entity so resp_check can not be used
if (resp.ok and
resp.status_code == NeutronResponseCodes.DELETE_SUBNET):
return result
err_msg = ('{subnet} Subnet Delete failure, expected status '
'code: {expected_status}. Response: {status} {reason} '
'{content}').format(
subnet=subnet_id,
expected_status=NeutronResponseCodes.DELETE_SUBNET,
status=resp.status_code, reason=resp.reason,
content=resp.content)
self._log.error(err_msg)
result.failures.append(err_msg)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to DELETE {0} subnet after {1} attempts: '
'{2}').format(subnet_id, resource_delete_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceDeleteException(err_msg)
return result
def clean_subnet(self, subnet_id, timeout=None, poll_interval=None):
"""
@summary: deletes a subnet within a time out
@param subnet_id: The UUID for the subnet
@type subnet_id: string
@param timeout: seconds to wait for the subnet to be deleted
@type timeout: int
@param poll_interval: sleep time interval between API delete/get calls
@type poll_interval: int
@return: None if delete was successful or the undeleted subnet_id
@rtype: None or string
"""
timeout = timeout or self.config.resource_delete_timeout
poll_interval = poll_interval or self.config.api_poll_interval
endtime = time.time() + int(timeout)
log_msg = 'Deleting {0} subnet within a {1}s timeout '.format(
subnet_id, timeout)
self._log.info(log_msg)
while time.time() < endtime:
try:
self.client.delete_subnet(subnet_id=subnet_id)
resp = self.client.get_subnet(subnet_id=subnet_id)
except Exception as err:
err_msg = ('Encountered an exception deleting a subnet with'
'the clean_subnet method. Exception: {0}').format(err)
self._log.error(err_msg)
if resp.status_code == NeutronResponseCodes.NOT_FOUND:
return None
time.sleep(poll_interval)
err_msg = 'Unable to delete {0} subnet within a {1}s timeout'.format(
subnet_id, timeout)
self._log.error(err_msg)
return subnet_id
def clean_subnets(self, subnets_list):
"""
@summary: deletes each subnet from a list calling clean_subnet
@param subnets_list: list of subnets UUIDs
@type subnets_list: list(str)
@return: list of undeleted subnets UUIDs
@rtype: list(str)
"""
log_msg = 'Deleting subnets: {0}'.format(subnets_list)
self._log.info(log_msg)
undeleted_subnets = []
for subnet in subnets_list:
result = self.clean_subnet(subnet_id=subnet)
if result:
undeleted_subnets.append(result)
if undeleted_subnets:
err_msg = 'Unable to delete subnets: {0}'.format(
undeleted_subnets)
self._log.error(err_msg)
return undeleted_subnets