Merge "Networking Parent behavior methods"

This commit is contained in:
Jenkins 2015-06-08 20:43:02 +00:00 committed by Gerrit Code Review
commit 5279061acf
7 changed files with 853 additions and 781 deletions

View File

@ -18,11 +18,14 @@ import requests
import time
from cafe.engine.behaviors import BaseBehavior
from cloudcafe.common.tools.datagen import rand_name
from cloudcafe.networking.networks.common.config import NetworkingBaseConfig
from cloudcafe.networking.networks.common.constants \
import NeutronResourceTypes, NeutronResponseCodes
import NeutronResponseCodes, NeutronResource
from cloudcafe.networking.networks.common.exceptions \
import UnhandledMethodCaseException
import ResourceBuildException, ResourceDeleteException, \
ResourceGetException, ResourceListException, ResourceUpdateException, \
UnhandledMethodCaseException
class NetworkingBaseBehaviors(BaseBehavior):
@ -155,13 +158,535 @@ class NetworkingBaseBehaviors(BaseBehavior):
id_list = [entity.id for entity in entity_list]
return id_list
def _delete_resources(self, resource_type, resource_list=None, name=None,
tenant_id=None, skip_delete=None):
def __over_limit_retry(self, resource_type, timeout, poll_interval,
status_code, resp, fn_name, fn_kwargs):
"""
@summary: deletes multiple resources (for ex. networks)
@summary: Retry mechanism for API rate limited calls
@param resource_type: type of resource for ex. networks, subnets, etc.
See NeutronResourceTypes in the networks constants
@type resource_type: str
@param timeout: timeout for over limit retries
@type timeout: int
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@param status_code: over limit API HTTP response code
@type: int
@param resp: API call response object
@type resp: Requests.response
@param fn_name: API function name
@type fn_name: str
@param fn_kwargs: API function arguments
@type fn_kwargs: dict
"""
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {timeout}s timeout '
'calling {resource_type} function {fn_name}').format(
timeout=timeout, resource_type=resource_type,
fn_name=fn_name)
self._log.info(retry_msg)
while (resp.status_code == status_code and
time.time() < endtime):
resp = getattr(self.client, fn_name)(**fn_kwargs)
time.sleep(poll_interval)
return resp
def _create_resource(self, resource, resource_build_attempts=None,
raise_exception=True, poll_interval=None,
has_name=True, use_exact_name=False,
attrs_kwargs=None, timeout=None,
use_over_limit_retry=False):
"""
@summary: Creates and verifies a resource is created as expected
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_build_attempts: number of API retries
@type resource_build_attempts: int
@param raise_exception: flag to raise an exception if the
resource was not created or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@param has_name: if the resource has a name attribute
@type has_name: bool
@param use_exact_name: flag if the exact name given should be used
@type use_exact_name: bool
@param attrs_kwargs: resource attributes to create with, for ex. name
@type attrs_kwargs: dict
@param timeout: resource create timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the create
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
# Defining the resource type in singular form (for ex. network)
resource_type = resource.singular
# If has_name is False name can be used as a reference for log messages
name = attrs_kwargs.get('name')
if has_name == True:
if name is None:
name = rand_name(self.config.starts_with_name)
elif not use_exact_name:
name = rand_name(name)
attrs_kwargs['name'] = name
else:
# In case name is NOT used as a reference for log messages
if name is None:
name = ''
poll_interval = poll_interval or self.config.api_poll_interval
resource_build_attempts = (resource_build_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_create_timeout
result = NetworkingResponse()
err_msg = '{0} Create failure'.format(resource_type)
for attempt in range(resource_build_attempts):
self._log.debug(
'Attempt {attempt_n} of {attempts} creating '
'{resource_type}'.format(attempt_n=attempt + 1,
attempts=resource_build_attempts,
resource_type=resource_type))
# Method uses resource type in singular form (slicing the ending s)
create_fn_name = 'create_{0}'.format(resource_type)
resp = getattr(self.client, create_fn_name)(**attrs_kwargs)
if use_over_limit_retry:
entity_too_large_status_code = (getattr(self.response_codes,
'REQUEST_ENTITY_TOO_LARGE'))
if resp.status_code == entity_too_large_status_code:
fn_kwargs = attrs_kwargs
resp = self.__over_limit_retry(
resource_type=resource_type, timeout=timeout,
poll_interval=poll_interval,
status_code=entity_too_large_status_code,
resp=resp, fn_name=create_fn_name,
fn_kwargs=fn_kwargs)
response_code = create_fn_name.upper()
status_code = getattr(self.response_codes, response_code)
resp_check = self.check_response(
resp=resp, status_code=status_code, 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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to CREATE {name} {resource_type} after '
'{attempts} attempts: {failures}').format(
name=name, resource_type=resource_type,
attempts=resource_build_attempts,
failures=result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceBuildException(err_msg)
return result
def _update_resource(self, resource, resource_id,
resource_update_attempts=None, raise_exception=False,
poll_interval=None, attrs_kwargs=None,
timeout=None, use_over_limit_retry=False):
"""
@summary: Updates and verifies a specified resource
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_id: The UUID for the resource
@type resource_id: str
@param resource_update_attempts: number of API retries
@type resource_update_attempts: int
@param raise_exception: flag to raise an exception if the
resource was not updated or to return None
@type raise_exception: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@param attrs_kwargs: resource attributes to update
@type attrs_kwargs: dict
@param timeout: resource update timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the update
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
# Defining the resource type in singular form (for ex. network)
resource_type = resource.singular
poll_interval = poll_interval or self.config.api_poll_interval
resource_update_attempts = (resource_update_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_update_timeout
result = NetworkingResponse()
err_msg = '{0} Update failure'.format(resource_type)
for attempt in range(resource_update_attempts):
self._log.debug(
'Attempt {attempt_n} of {attempts} updating {resource_type} '
'{resource_id}'.format(attempt_n=attempt + 1,
attempts=resource_update_attempts,
resource_type=resource_type,
resource_id=resource_id))
# Method uses resource type in singular form (slicing the ending s)
update_fn_name = 'update_{0}'.format(resource_type)
# Resource ID is expected to be the first client method parameter
resp = getattr(self.client, update_fn_name)(resource_id,
**attrs_kwargs)
if use_over_limit_retry:
entity_too_large_status_code = (getattr(self.response_codes,
'REQUEST_ENTITY_TOO_LARGE'))
if resp.status_code == entity_too_large_status_code:
fn_kwargs = attrs_kwargs
# Adding the resource id to the function kwargs
resource_id_name = '{0}_id'.format(resource_type)
fn_kwargs[resource_id_name] = resource_id
resp = self.__over_limit_retry(
resource_type=resource_type, timeout=timeout,
poll_interval=poll_interval,
status_code=entity_too_large_status_code,
resp=resp, fn_name=update_fn_name,
fn_kwargs=fn_kwargs)
response_code = update_fn_name.upper()
status_code = getattr(self.response_codes, response_code)
resp_check = self.check_response(
resp=resp, status_code=status_code, label=resource_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 {resource_id} {resource_type} after '
'{attempts} attempts: {failures}').format(
resource_id=resource_id, resource_type=resource_type,
attempts=resource_update_attempts,
failures=result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceUpdateException(err_msg)
return result
def _get_resource(self, resource, resource_id,
resource_get_attempts=None, raise_exception=False,
poll_interval=None, timeout=None,
use_over_limit_retry=False):
"""
@summary: Shows and verifies a specified resource
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_id: The UUID for the resource
@type resource_id: str
@param resource_get_attempts: number of API retries
@type resource_get_attempts: int
@param raise_exception: flag to raise an exception if the get
resource 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
@param timeout: resource get timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the get
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
# Defining the resource type in singular form (for ex. network)
resource_type = resource.singular
poll_interval = poll_interval or self.config.api_poll_interval
resource_get_attempts = (resource_get_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_get_timeout
result = NetworkingResponse()
err_msg = '{0} Get failure'.format(resource_type)
for attempt in range(resource_get_attempts):
self._log.debug(
'Attempt {attempt_n} of {attempts} getting {resource_type} '
'{resource_id}'.format(attempt_n=attempt + 1,
attempts=resource_get_attempts,
resource_type=resource_type,
resource_id=resource_id))
# Method uses resource type in singular form (slicing the ending s)
get_fn_name = 'get_{0}'.format(resource_type)
resp = getattr(self.client, get_fn_name)(resource_id)
if use_over_limit_retry:
entity_too_large_status_code = (getattr(self.response_codes,
'REQUEST_ENTITY_TOO_LARGE'))
if resp.status_code == entity_too_large_status_code:
fn_kwargs = {}
# Adding the resource id to the function kwargs
resource_id_name = '{0}_id'.format(resource_type)
fn_kwargs[resource_id_name] = resource_id
resp = self.__over_limit_retry(
resource_type=resource_type, timeout=timeout,
poll_interval=poll_interval,
status_code=entity_too_large_status_code,
resp=resp, fn_name=get_fn_name,
fn_kwargs=fn_kwargs)
response_code = get_fn_name.upper()
status_code = getattr(self.response_codes, response_code)
resp_check = self.check_response(resp=resp,
status_code=status_code,
label=resource_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 {resource_id} {resource_type} after {attempts} '
'attempts: {failures}').format(resource_id=resource_id,
resource_type=resource_type,
attempts=resource_get_attempts,
failures=result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceGetException(err_msg)
return result
def _list_resources(self, resource, resource_list_attempts=None,
raise_exception=False, poll_interval=None,
params_kwargs=None, timeout=None,
use_over_limit_retry=False):
"""
@summary: Lists resources and verifies the response is the expected
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_list_attempts: number of API retries
@type resource_list_attempts: int
@param raise_exception: flag to raise an exception if the resource list
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
@param params_kwargs: key value params to filter by the list results
@type params_kwargs: dict
@param timeout: resource list timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the list
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
# Defining the resource type in plural form (for ex. networks)
resource_type = resource.plural
poll_interval = poll_interval or self.config.api_poll_interval
resource_list_attempts = (resource_list_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_get_timeout
result = NetworkingResponse()
err_msg = '{0} list failure'.format(resource_type)
for attempt in range(resource_list_attempts):
self._log.debug(
'Attempt {attempt_n} of {attempts} with {resource_type} '
'list'.format(attempt_n=attempt + 1,
attempts=resource_list_attempts,
resource_type=resource_type))
list_fn_name = 'list_{0}'.format(resource_type)
resp = getattr(self.client, list_fn_name)(**params_kwargs)
if use_over_limit_retry:
entity_too_large_status_code = (getattr(self.response_codes,
'REQUEST_ENTITY_TOO_LARGE'))
if resp.status_code == entity_too_large_status_code:
fn_kwargs = params_kwargs
resp = self.__over_limit_retry(
resource_type=resource_type, timeout=timeout,
poll_interval=poll_interval,
status_code=entity_too_large_status_code,
resp=resp, fn_name=list_fn_name,
fn_kwargs=fn_kwargs)
response_code = list_fn_name.upper()
status_code = getattr(self.response_codes, response_code)
resp_check = self.check_response(
resp=resp, status_code=status_code, 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 {resource_type} after {attempts} attempts: '
'{failures}').format(resource_type=resource_type,
attempts=resource_list_attempts,
failures=result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceListException(err_msg)
return result
def _delete_resource(self, resource, resource_id,
resource_delete_attempts=None, raise_exception=False,
poll_interval=None, timeout=None,
use_over_limit_retry=False):
"""
@summary: Deletes and verifies a specified resource is deleted
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_id: The UUID for the resource
@type resource_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
resource 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
@param timeout: resource delete timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the delete
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@rtype: common.behaviors.NetworkingResponse
"""
# Defining the resource type in singular form (for ex. network)
resource_type = resource.singular
poll_interval = poll_interval or self.config.api_poll_interval
resource_delete_attempts = (resource_delete_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_get_timeout
result = NetworkingResponse()
for attempt in range(resource_delete_attempts):
self._log.debug(
'Attempt {attempt_n} of {attempts} deleting {resource_type} '
'{resource_id}'.format(attempt_n=attempt + 1,
attempts=resource_delete_attempts,
resource_type=resource_type,
resource_id=resource_id))
# Method uses resource type in singular form (slicing the ending s)
delete_fn_name = 'delete_{0}'.format(resource_type)
resp = getattr(self.client, delete_fn_name)(resource_id)
if use_over_limit_retry:
entity_too_large_status_code = (getattr(self.response_codes,
'REQUEST_ENTITY_TOO_LARGE'))
if resp.status_code == entity_too_large_status_code:
fn_kwargs = {}
# Adding the resource id to the function kwargs
resource_id_name = '{0}_id'.format(resource_type)
fn_kwargs[resource_id_name] = resource_id
resp = self.__over_limit_retry(
resource_type=resource_type, timeout=timeout,
poll_interval=poll_interval,
status_code=entity_too_large_status_code,
resp=resp, fn_name=delete_fn_name,
fn_kwargs=fn_kwargs)
result.response = resp
# Delete response is without entity so resp_check can not be used
response_code = delete_fn_name.upper()
status_code = getattr(self.response_codes, response_code)
if resp.ok and resp.status_code == status_code:
return result
err_msg = ('{resource_id} {resource_type} Delete failure, expected'
'status code: {expected_status}. Response: {status} '
'{reason} {content}').format(
resource_id=resource_id,
resource_type=resource_type,
expected_status=status_code,
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 {resource_id} {resource_type} after '
'{attempts} attempts: {failures}').format(
resource_id=resource_id, resource_type=resource_type,
attempts=resource_delete_attempts,
failures=result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceDeleteException(err_msg)
return result
def _delete_resources(self, resource, resource_list=None, name=None,
tenant_id=None, skip_delete=None):
"""
@summary: deletes multiple resources (for ex. networks)
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_list: list of resource UUIDs
@type resource_list: list(str)
@param name: resource name to filter by, asterisk can be used at the
@ -175,18 +700,23 @@ class NetworkingBaseBehaviors(BaseBehavior):
@return: failed delete list with resource UUIDs and failures
@rtype: list(dict)
"""
# Defining the resource type in singular and plural forms
resource_type_singular = resource.singular
resource_type_plural = resource.plural
# Getting the resource list based on the resource type (if not given)
if resource_list is None:
list_fn_name = 'list_{0}'.format(resource_type)
list_fn_name = 'list_{0}'.format(resource_type_plural)
resp = getattr(self, list_fn_name)(tenant_id=tenant_id)
# Getting the Neutron expected response based on the fn name
response_code = list_fn_name.upper()
status_code = getattr(NeutronResponseCodes, response_code)
status_code = getattr(self.response_codes, response_code)
if resp.response.status_code != status_code:
get_msg = 'Unable to get {0} for delete_{0} call'.format(
resource_type)
resource_type_plural)
self._log.info(get_msg)
return None
resources = resp.response.entity
@ -205,7 +735,7 @@ class NetworkingBaseBehaviors(BaseBehavior):
if skip_delete is not None:
do_not_delete.extend(skip_delete)
if resource_type == NeutronResourceTypes.NETWORKS:
if resource_type_plural == NeutronResource.NETWORKS:
property_list = ['public_network_id', 'service_network_id']
for prop in property_list:
if (hasattr(self.config, prop) and
@ -217,16 +747,114 @@ class NetworkingBaseBehaviors(BaseBehavior):
if resource_to_skip in resource_list:
resource_list.remove(resource_to_skip)
log_msg = 'Deleting {0}: {1}'.format(resource_type, resource_list)
log_msg = 'Deleting {0}: {1}'.format(resource_type_plural,
resource_list)
self._log.info(log_msg)
failed_deletes = []
delete_fn_name = 'delete_{0}'.format(resource_type[:-1])
delete_fn_name = 'delete_{0}'.format(resource_type_singular)
for resource_id in resource_list:
result = getattr(self, delete_fn_name)(resource_id)
if result.failures:
failed_deletes.append(result.failures)
return failed_deletes
def _clean_resource(self, resource, resource_id, timeout=None,
poll_interval=None):
"""
@summary: deletes a resource within a time out
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_id: The UUID for the for the resource
@type resource_id: str
@param timeout: seconds to wait for the resource 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 resource_id
@rtype: None or string
"""
# Defining the resource type in singular form (for ex. network)
resource_type = resource.singular
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 {resource_id} {resource_type} within a {timeout}s'
' timeout').format(resource_id=resource_id,
resource_type=resource_type,
timeout=timeout)
self._log.info(log_msg)
# Method uses resource type in singular form (slicing the ending s)
delete_fn_name = 'delete_{0}'.format(resource_type)
get_fn_name = 'get_{0}'.format(resource_type)
resp = None
while time.time() < endtime:
try:
getattr(self.client, delete_fn_name)(resource_id)
resp = getattr(self.client, get_fn_name)(resource_id)
except Exception as err:
err_msg = ('Encountered an exception deleting a '
'{resource_type} within the _clean_resource method.'
' Exception: {error}').format(
resource_type=resource_type, error=err)
self._log.error(err_msg)
if (resp is not None and
resp.status_code == NeutronResponseCodes.NOT_FOUND):
return None
time.sleep(poll_interval)
err_msg = ('Unable to delete {resource_id} {resource_type} within a '
'{timeout}s timeout').format(resource_id=resource_id,
resource_type=resource_type,
timeout=timeout)
self._log.error(err_msg)
return resource_id
def _clean_resources(self, resource, resource_list, timeout=None,
poll_interval=None):
"""
@summary: deletes each resource from a list calling _clean_resource
@param resource: type of resource for ex. network, subnet, port, etc.
See NeutronResource in the networks constants
@type resource: resource instance with singular and plural forms
@param resource_list: list of resource UUIDs to delete
@type resource_list: list(str)
@param timeout: seconds to wait for the resource to be deleted
@type timeout: int
@param poll_interval: sleep time interval between API delete/get calls
@type poll_interval: int
@return: list of undeleted resource UUIDs
@rtype: list(str)
"""
# Defining the resource type in plural form (for ex. networks)
resource_type_plural = resource.plural
log_msg = 'Deleting {resource_type}: {resource_list}'.format(
resource_type=resource_type_plural, resource_list=resource_list)
self._log.info(log_msg)
undeleted_resources = []
for resource_id in resource_list:
# _cleanup_resource takes the resource obj
result = self._clean_resource(resource=resource,
resource_id=resource_id,
timeout=timeout,
poll_interval=poll_interval)
if result:
undeleted_resources.append(result)
if undeleted_resources:
err_msg = ('Unable to delete {resource_type}: '
'{undeleted_resources}').format(
resource_type=resource_type_plural,
undeleted_resources=undeleted_resources)
self._log.error(err_msg)
return undeleted_resources
class NetworkingResponse(object):
"""

View File

@ -60,6 +60,11 @@ class NetworkingBaseConfig(ConfigSectionInterface):
"""Number of times to retry an API call by a behavior method"""
return int(self.get("api_retries", 1))
@property
def use_over_limit_retry(self):
"""Flag to enable/disable retries due to over limits responses"""
return self.get_boolean("use_over_limit_retry", False)
@property
def resource_create_timeout(self):
"""Seconds to wait for creating a resource"""

View File

@ -15,13 +15,25 @@ limitations under the License.
"""
class NeutronResourceTypes(object):
class NeutronResource(object):
"""Neutron resource types"""
NETWORK = 'network'
NETWORKS = 'networks'
SUBNET = 'subnet'
SUBNETS = 'subnets'
PORT = 'port'
PORTS = 'ports'
PLURALS = {NETWORK: NETWORKS, SUBNET: SUBNETS, PORT: PORTS}
def __init__(self, singular_type):
self.singular = singular_type
@property
def plural(self):
return self.PLURALS.get(self.singular, self.singular)
class NeutronResponseCodes(object):
"""HTTP Neutron API Response codes"""

View File

@ -14,16 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
"""
import time
from cloudcafe.common.tools.datagen import rand_name
from cloudcafe.networking.networks.common.behaviors \
import NetworkingBaseBehaviors, NetworkingResponse
import NetworkingBaseBehaviors
from cloudcafe.networking.networks.common.constants \
import NeutronResourceTypes, NeutronResponseCodes
from cloudcafe.networking.networks.common.exceptions \
import ResourceBuildException, ResourceDeleteException,\
ResourceGetException, ResourceListException, ResourceUpdateException
import NeutronResource, NeutronResponseCodes
class NetworksBehaviors(NetworkingBaseBehaviors):
@ -32,6 +26,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
super(NetworksBehaviors, self).__init__()
self.config = networks_config
self.client = networks_client
self.response_codes = NeutronResponseCodes
self.networks_resource = NeutronResource(NeutronResource.NETWORK)
def create_network(self, name=None, admin_state_up=None, shared=None,
tenant_id=None, resource_build_attempts=None,
@ -59,46 +55,16 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@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)
elif not use_exact_name:
name = rand_name(name)
attrs_kwargs = dict(name=name, admin_state_up=admin_state_up,
shared=shared, tenant_id=tenant_id)
poll_interval = poll_interval or self.config.api_poll_interval
resource_build_attempts = (resource_build_attempts or
self.config.api_retries)
result = self._create_resource(
resource=self.networks_resource,
resource_build_attempts=resource_build_attempts,
raise_exception=raise_exception, use_exact_name=use_exact_name,
poll_interval=poll_interval, attrs_kwargs=attrs_kwargs)
result = NetworkingResponse()
err_msg = 'Network Create failure'
for attempt in range(resource_build_attempts):
self._log.debug('Attempt {0} of {1} building network {2}'.format(
attempt + 1, resource_build_attempts, name))
resp = self.client.create_network(
name=name, admin_state_up=admin_state_up, shared=shared,
tenant_id=tenant_id)
resp_check = self.check_response(resp=resp,
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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to create {0} network after {1} attempts: '
'{2}').format(name, resource_build_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceBuildException(err_msg)
return result
return result
def update_network(self, network_id, name=None, admin_state_up=None,
shared=None, tenant_id=None,
@ -130,43 +96,17 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@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)
attrs_kwargs = dict(name=name, admin_state_up=admin_state_up,
shared=shared, tenant_id=tenant_id)
result = NetworkingResponse()
err_msg = 'Network Update failure'
for attempt in range(resource_update_attempts):
self._log.debug('Attempt {0} of {1} updating network {2}'.format(
attempt + 1, resource_update_attempts, network_id))
result = self._update_resource(
resource=self.networks_resource,
resource_id=network_id,
resource_update_attempts=resource_update_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
attrs_kwargs=attrs_kwargs)
resp = self.client.update_network(
network_id=network_id, name=name,
admin_state_up=admin_state_up, shared=shared,
tenant_id=tenant_id)
resp_check = self.check_response(resp=resp,
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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to update {0} network after {1} attempts: '
'{2}').format(network_id, resource_update_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceUpdateException(err_msg)
return result
return result
def get_network(self, network_id, resource_get_attempts=None,
raise_exception=False, poll_interval=None):
@ -184,40 +124,13 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@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 = self._get_resource(
resource=self.networks_resource,
resource_id=network_id,
resource_get_attempts=resource_get_attempts,
raise_exception=raise_exception, poll_interval=poll_interval)
result = NetworkingResponse()
err_msg = 'Network 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, network_id))
resp = self.client.get_network(network_id=network_id)
resp_check = self.check_response(resp=resp,
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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to GET {0} network after {1} attempts: '
'{2}').format(network_id, resource_get_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceGetException(err_msg)
return result
return result
def list_networks(self, network_id=None, name=None, status=None,
admin_state_up=None, shared=None, tenant_id=None,
@ -254,43 +167,18 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@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)
params_kwargs = dict(network_id=network_id, name=name, status=status,
admin_state_up=admin_state_up, shared=shared,
tenant_id=tenant_id, limit=limit, marker=marker,
page_reverse=page_reverse)
result = NetworkingResponse()
err_msg = 'Network List failure'
for attempt in range(resource_list_attempts):
self._log.debug('Attempt {0} of {1} with network list'.format(
attempt + 1, resource_list_attempts))
result = self._list_resources(
resource=self.networks_resource,
resource_list_attempts=resource_list_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
params_kwargs=params_kwargs)
resp = self.client.list_networks(
network_id=network_id, name=name, status=status,
admin_state_up=admin_state_up, shared=shared,
tenant_id=tenant_id, limit=limit, marker=marker,
page_reverse=page_reverse)
resp_check = self.check_response(resp=resp,
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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to LIST networks after {0} attempts: '
'{1}').format(resource_list_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceListException(err_msg)
return result
return result
def delete_network(self, network_id, resource_delete_attempts=None,
raise_exception=False, poll_interval=None):
@ -308,43 +196,13 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@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 = self._delete_resource(
resource=self.networks_resource,
resource_id=network_id,
resource_delete_attempts=resource_delete_attempts,
raise_exception=raise_exception, poll_interval=poll_interval)
result = NetworkingResponse()
for attempt in range(resource_delete_attempts):
self._log.debug('Attempt {0} of {1} deleting network {2}'.format(
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):
return result
err_msg = ('{network} Network Delete failure, expected status '
'code: {expected_status}. Response: {status} {reason} '
'{content}').format(
network=network_id,
expected_status=NeutronResponseCodes.DELETE_NETWORK,
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} network after {1} attempts: '
'{2}').format(network_id, resource_delete_attempts,
result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceDeleteException(err_msg)
return result
return result
def delete_networks(self, network_list=None, name=None, tenant_id=None,
skip_delete=None):
@ -366,7 +224,8 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
result = self._delete_resources(
resource_list=network_list, name=name,
tenant_id=tenant_id, skip_delete=skip_delete,
resource_type=NeutronResourceTypes.NETWORKS)
resource=self.networks_resource)
return result
def clean_network(self, network_id, timeout=None, poll_interval=None):
@ -381,31 +240,12 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@return: None if delete was successful or the undeleted network_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} network within a {1}s timeout '.format(
network_id, timeout)
self._log.info(log_msg)
resp = None
while time.time() < endtime:
try:
self.client.delete_network(network_id=network_id)
resp = self.client.get_network(network_id=network_id)
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)
result = self._clean_resource(
resource=self.networks_resource,
resource_id=network_id,
timeout=timeout, poll_interval=poll_interval)
if (resp is not None and
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)
return network_id
return result
def clean_networks(self, networks_list, timeout=None, poll_interval=None):
"""
@ -419,16 +259,9 @@ class NetworksBehaviors(NetworkingBaseBehaviors):
@return: list of undeleted networks UUIDs
@rtype: list(str)
"""
log_msg = 'Deleting networks: {0}'.format(networks_list)
self._log.info(log_msg)
undeleted_networks = []
for network in networks_list:
result = self.clean_network(network_id=network, timeout=timeout,
poll_interval=poll_interval)
if result:
undeleted_networks.append(result)
if undeleted_networks:
err_msg = 'Unable to delete networks: {0}'.format(
undeleted_networks)
self._log.error(err_msg)
return undeleted_networks
result = self._clean_resources(
resource=self.networks_resource,
resource_list=networks_list,
timeout=timeout, poll_interval=poll_interval)
return result

View File

@ -16,15 +16,12 @@ limitations under the License.
import netaddr
import time
from cloudcafe.common.tools.datagen import rand_name
from cloudcafe.networking.networks.common.behaviors \
import NetworkingBaseBehaviors, NetworkingResponse
import NetworkingBaseBehaviors
from cloudcafe.networking.networks.common.constants \
import NeutronResponseCodes, NeutronResourceTypes
import NeutronResponseCodes, NeutronResource
from cloudcafe.networking.networks.common.exceptions \
import NetworkIDMissingException, ResourceBuildException,\
ResourceDeleteException, ResourceGetException, ResourceListException,\
ResourceUpdateException
import NetworkIDMissingException
class PortsBehaviors(NetworkingBaseBehaviors):
@ -33,6 +30,8 @@ class PortsBehaviors(NetworkingBaseBehaviors):
super(PortsBehaviors, self).__init__()
self.config = ports_config
self.client = ports_client
self.response_codes = NeutronResponseCodes
self.ports_resource = NeutronResource(NeutronResource.PORT)
def get_subnet_ids_from_fixed_ips(self, fixed_ips):
"""
@ -70,7 +69,7 @@ class PortsBehaviors(NetworkingBaseBehaviors):
device_owner=None, tenant_id=None, security_groups=None,
resource_build_attempts=None, raise_exception=True,
use_exact_name=False, poll_interval=None,
timeout=None, use_over_limit_retry=None):
timeout=None, use_over_limit_retry=False):
"""
@summary: Creates and verifies a Port is created as expected
@param network_id: network port is associated with (CRUD: CR)
@ -104,9 +103,9 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@type use_exact_name: bool
@param poll_interval: sleep time interval between API retries
@type poll_interval: int
@param timeout: port update timeout for over limit retries
@param timeout: port create timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the port update
@param use_over_limit_retry: flag to enable/disable the port create
over limits retries
@type use_over_limit_retry: bool
@return: NetworkingResponse object with api response and failure list
@ -115,74 +114,27 @@ class PortsBehaviors(NetworkingBaseBehaviors):
if not network_id:
raise NetworkIDMissingException
if name is None:
name = rand_name(self.config.starts_with_name)
elif not use_exact_name:
name = rand_name(name)
attrs_kwargs = dict(
network_id=network_id, name=name,
admin_state_up=admin_state_up, mac_address=mac_address,
fixed_ips=fixed_ips, device_id=device_id,
device_owner=device_owner, tenant_id=tenant_id,
security_groups=security_groups)
poll_interval = poll_interval or self.config.api_poll_interval
resource_build_attempts = (resource_build_attempts or
self.config.api_retries)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_create_timeout
result = self._create_resource(
resource=self.ports_resource,
resource_build_attempts=resource_build_attempts,
raise_exception=raise_exception, use_exact_name=use_exact_name,
poll_interval=poll_interval, attrs_kwargs=attrs_kwargs,
timeout=timeout, use_over_limit_retry=use_over_limit_retry)
result = NetworkingResponse()
err_msg = 'Port Create failure'
for attempt in range(resource_build_attempts):
self._log.debug('Attempt {0} of {1} building port {2}'.format(
attempt + 1, resource_build_attempts, name))
resp = self.client.create_port(
network_id=network_id, name=name,
admin_state_up=admin_state_up, mac_address=mac_address,
fixed_ips=fixed_ips, device_id=device_id,
device_owner=device_owner, tenant_id=tenant_id,
security_groups=security_groups)
if use_over_limit_retry:
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {0}s timeout creating a '
'port on network {1}').format(timeout, network_id)
self._log.info(retry_msg)
while (resp.status_code ==
NeutronResponseCodes.REQUEST_ENTITY_TOO_LARGE and
time.time() < endtime):
resp = self.client.create_port(
network_id=network_id, name=name,
admin_state_up=admin_state_up, mac_address=mac_address,
fixed_ips=fixed_ips, device_id=device_id,
device_owner=device_owner, tenant_id=tenant_id,
security_groups=security_groups)
time.sleep(poll_interval)
resp_check = self.check_response(resp=resp,
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
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to create {0} port after {1} attempts: '
'{2}').format(name, resource_build_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceBuildException(err_msg)
return result
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,
timeout=None, use_over_limit_retry=None):
timeout=None, use_over_limit_retry=False):
"""
@summary: Updates and verifies a specified Port
@param port_id: The UUID for the port
@ -219,66 +171,24 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@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)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_update_timeout
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,
attrs_kwargs = dict(
name=name, admin_state_up=admin_state_up,
fixed_ips=fixed_ips, device_id=device_id,
device_owner=device_owner, security_groups=security_groups)
if use_over_limit_retry:
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {0}s timeout updating '
'port {1}').format(timeout, port_id)
self._log.info(retry_msg)
while (resp.status_code ==
NeutronResponseCodes.REQUEST_ENTITY_TOO_LARGE and
time.time() < endtime):
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)
time.sleep(poll_interval)
result = self._update_resource(
resource=self.ports_resource,
resource_id=port_id,
resource_update_attempts=resource_update_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
attrs_kwargs=attrs_kwargs, timeout=timeout,
use_over_limit_retry=use_over_limit_retry)
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
return result
def get_port(self, port_id, resource_get_attempts=None,
raise_exception=False, poll_interval=None,
timeout=None, use_over_limit_retry=None):
timeout=None, use_over_limit_retry=False):
"""
@summary: Shows and verifies a specified port
@param port_id: The UUID for the port
@ -292,67 +202,27 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@type poll_interval: int
@param timeout: port get timeout for over limit retries
@type timeout: int
@param use_over_limit_retry: flag to enable/disable the port update
@param use_over_limit_retry: flag to enable/disable the port get
over limits retries
@type use_over_limit_retry: bool
@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)
poll_interval = poll_interval or self.config.api_poll_interval
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_get_timeout
result = self._get_resource(
resource=self.ports_resource,
resource_id=port_id,
resource_get_attempts=resource_get_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
timeout=timeout, use_over_limit_retry=use_over_limit_retry)
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)
if use_over_limit_retry:
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {0}s timeout getting '
'port {1}').format(timeout, port_id)
self._log.info(retry_msg)
while (resp.status_code ==
NeutronResponseCodes.REQUEST_ENTITY_TOO_LARGE and
time.time() < endtime):
resp = self.client.get_port(port_id=port_id)
time.sleep(poll_interval)
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
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, timeout=None,
use_over_limit_retry=None):
use_over_limit_retry=False):
"""
@summary: Lists ports and verifies the response is the expected
@param port_id: The UUID for the port to filter by
@ -394,67 +264,25 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@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)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_get_timeout
params_kwargs = dict(
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)
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))
result = self._list_resources(
resource=self.ports_resource,
resource_list_attempts=resource_list_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
params_kwargs=params_kwargs, timeout=timeout,
use_over_limit_retry=use_over_limit_retry)
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)
if use_over_limit_retry:
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {0}s timeout listing '
'ports').format(timeout, port_id)
self._log.info(retry_msg)
while (resp.status_code ==
NeutronResponseCodes.REQUEST_ENTITY_TOO_LARGE and
time.time() < endtime):
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)
time.sleep(poll_interval)
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
return result
def delete_port(self, port_id, resource_delete_attempts=None,
raise_exception=False, poll_interval=None,
timeout=None, use_over_limit_retry=None):
timeout=None, use_over_limit_retry=False):
"""
@summary: Deletes and verifies a specified port is deleted
@param string port_id: The UUID for the port
@ -474,58 +302,14 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@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)
use_over_limit_retry = (use_over_limit_retry or
self.config.use_over_limit_retry)
timeout = timeout or self.config.resource_delete_timeout
result = self._delete_resource(
resource=self.ports_resource,
resource_id=port_id,
resource_delete_attempts=resource_delete_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
timeout=timeout, use_over_limit_retry=use_over_limit_retry)
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)
if use_over_limit_retry:
endtime = time.time() + int(timeout)
retry_msg = ('OverLimit retry with a {0}s timeout deleting '
'port {1}').format(timeout, port_id)
self._log.info(retry_msg)
while (resp.status_code ==
NeutronResponseCodes.REQUEST_ENTITY_TOO_LARGE and
time.time() < endtime):
resp = self.client.delete_port(port_id=port_id)
time.sleep(poll_interval)
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
return result
def delete_ports(self, port_list=None, name=None, tenant_id=None,
skip_delete=None):
@ -547,7 +331,7 @@ class PortsBehaviors(NetworkingBaseBehaviors):
result = self._delete_resources(
resource_list=port_list, name=name,
tenant_id=tenant_id, skip_delete=skip_delete,
resource_type=NeutronResourceTypes.PORTS)
resource=self.ports_resource)
return result
def clean_port(self, port_id, timeout=None, poll_interval=None):
@ -562,32 +346,12 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@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
result = self._clean_resource(
resource=self.ports_resource,
resource_id=port_id,
timeout=timeout, poll_interval=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)
resp = None
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 is not None and
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
return result
def clean_ports(self, ports_list, timeout=None, poll_interval=None):
"""
@ -601,16 +365,9 @@ class PortsBehaviors(NetworkingBaseBehaviors):
@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, timeout=timeout,
poll_interval=poll_interval)
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
result = self._clean_resources(
resource=self.ports_resource,
resource_list=ports_list,
timeout=timeout, poll_interval=poll_interval)
return result

View File

@ -47,11 +47,6 @@ class PortsConfig(NetworkingBaseConfig):
"""Ports fixed IPs quota"""
return int(self.get("fixed_ips_per_port", 5))
@property
def use_over_limit_retry(self):
"""Flag to enable/disable retries due to over limits responses"""
return self.get_boolean("use_over_limit_retry", False)
@property
def api_poll_interval(self):
"""Time interval for api calls on retry loops"""

View File

@ -21,15 +21,13 @@ import IPy
import netaddr
from cloudcafe.common.tools.datagen import rand_name, random_cidr
from cloudcafe.common.tools.datagen import random_cidr
from cloudcafe.networking.networks.common.behaviors \
import NetworkingBaseBehaviors, NetworkingResponse
import NetworkingBaseBehaviors
from cloudcafe.networking.networks.common.constants \
import NeutronResponseCodes, NeutronResourceTypes
import NeutronResponseCodes, NeutronResource
from cloudcafe.networking.networks.common.exceptions \
import InvalidIPException, NetworkIDMissingException,\
ResourceBuildException, ResourceDeleteException, ResourceGetException,\
ResourceListException, ResourceUpdateException
import InvalidIPException, NetworkIDMissingException
class SubnetsBehaviors(NetworkingBaseBehaviors):
@ -38,6 +36,8 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
super(SubnetsBehaviors, self).__init__()
self.config = subnets_config
self.client = subnets_client
self.response_codes = NeutronResponseCodes
self.subnets_resource = NeutronResource(NeutronResource.SUBNET)
def verify_ip(self, ip_cidr, ip_range=None):
"""
@ -517,49 +517,20 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
ip_version = 4
cidr = self.create_ipv4_cidr()
if name is None:
name = rand_name(self.config.starts_with_name)
elif not use_exact_name:
name = rand_name(name)
attrs_kwargs = dict(
network_id=network_id, ip_version=ip_version, cidr=cidr,
name=name, tenant_id=tenant_id, gateway_ip=gateway_ip,
dns_nameservers=dns_nameservers,
allocation_pools=allocation_pools, host_routes=host_routes,
enable_dhcp=enable_dhcp)
poll_interval = poll_interval or self.config.api_poll_interval
resource_build_attempts = (resource_build_attempts or
self.config.api_retries)
result = self._create_resource(
resource=self.subnets_resource,
resource_build_attempts=resource_build_attempts,
raise_exception=raise_exception, use_exact_name=use_exact_name,
poll_interval=poll_interval, attrs_kwargs=attrs_kwargs)
result = NetworkingResponse()
err_msg = 'Subnet Create failure'
for attempt in range(resource_build_attempts):
self._log.debug('Attempt {0} of {1} building subnet {2}'.format(
attempt + 1, resource_build_attempts, name))
resp = self.client.create_subnet(
network_id=network_id, ip_version=ip_version, cidr=cidr,
name=name, tenant_id=tenant_id, gateway_ip=gateway_ip,
dns_nameservers=dns_nameservers,
allocation_pools=allocation_pools, host_routes=host_routes,
enable_dhcp=enable_dhcp)
resp_check = self.check_response(resp=resp,
status_code=NeutronResponseCodes.CREATE_SUBNET, 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 update was successful the
# first time
result.failures.append(resp_check)
time.sleep(poll_interval)
else:
err_msg = (
'Unable to create {0} subnet after {1} attempts: '
'{2}').format(name, resource_build_attempts, result.failures)
self._log.error(err_msg)
if raise_exception:
raise ResourceBuildException(err_msg)
return result
return result
def update_subnet(self, subnet_id, name=None, gateway_ip=None,
dns_nameservers=None, host_routes=None,
@ -597,43 +568,19 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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)
attrs_kwargs = dict(
name=name, gateway_ip=gateway_ip,
dns_nameservers=dns_nameservers, host_routes=host_routes,
enable_dhcp=enable_dhcp, allocation_pools=allocation_pools)
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))
result = self._update_resource(
resource=self.subnets_resource,
resource_id=subnet_id,
resource_update_attempts=resource_update_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
attrs_kwargs=attrs_kwargs)
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
return result
def get_subnet(self, subnet_id, resource_get_attempts=None,
raise_exception=False, poll_interval=None):
@ -651,40 +598,13 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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 = self._get_resource(
resource=self.subnets_resource,
resource_id=subnet_id,
resource_get_attempts=resource_get_attempts,
raise_exception=raise_exception, poll_interval=poll_interval)
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
return result
def list_subnets(self, subnet_id=None, network_id=None, cidr=None,
tenant_id=None, gateway_ip=None, ip_version=None,
@ -725,43 +645,19 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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)
params_kwargs = dict(
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)
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))
result = self._list_resources(
resource=self.subnets_resource,
resource_list_attempts=resource_list_attempts,
raise_exception=raise_exception, poll_interval=poll_interval,
params_kwargs=params_kwargs)
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
return result
def delete_subnet(self, subnet_id, resource_delete_attempts=None,
raise_exception=False, poll_interval=None):
@ -779,43 +675,13 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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 = self._delete_resource(
resource=self.subnets_resource,
resource_id=subnet_id,
resource_delete_attempts=resource_delete_attempts,
raise_exception=raise_exception, poll_interval=poll_interval)
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
return result
def delete_subnets(self, subnet_list=None, name=None, tenant_id=None,
skip_delete=None):
@ -837,7 +703,8 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
result = self._delete_resources(
resource_list=subnet_list, name=name,
tenant_id=tenant_id, skip_delete=skip_delete,
resource_type=NeutronResourceTypes.SUBNETS)
resource=self.subnets_resource)
return result
def clean_subnet(self, subnet_id, timeout=None, poll_interval=None):
@ -852,30 +719,12 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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)
resp = None
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 is not None and
resp.status_code == NeutronResponseCodes.NOT_FOUND):
return None
time.sleep(poll_interval)
result = self._clean_resource(
resource=self.subnets_resource,
resource_id=subnet_id,
timeout=timeout, poll_interval=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
return result
def clean_subnets(self, subnets_list, timeout=None, poll_interval=None):
"""
@ -889,16 +738,9 @@ class SubnetsBehaviors(NetworkingBaseBehaviors):
@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, timeout=timeout,
poll_interval=poll_interval)
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
result = self._clean_resources(
resource=self.subnets_resource,
resource_list=subnets_list,
timeout=timeout, poll_interval=poll_interval)
return result