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:
parent
71fbeb4742
commit
cd47e56366
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user