Merge "Networking Parent behavior methods"
This commit is contained in:
commit
5279061acf
@ -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):
|
||||
"""
|
||||
|
@ -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"""
|
||||
|
@ -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"""
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"""
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user