Networking resource management tool
- Adding the networking Resources tool for managing networking related resources like: servers, keypairs networks, subnets, ports and security groups. Managing involves listing and deleting resources - Updating the delete_keypairs, wait_for_servers_to_be_deleted and _wait_for_compute_delete networking behavior methods for better use by the Resources tool. - Updating the check_response networking base behavior method to make optional the check for entity. - Adding the get_name_list_from_entity_list base behavior method - Updating the DELETE_KEYPAIR constant Change-Id: Ifa78e8d59543fbe3721d9e61f44d2e65a9ba884f
This commit is contained in:
parent
d0863e0b16
commit
de93ab7732
|
@ -521,14 +521,20 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
|||
keypair_list = self.list_keypairs(name=name)
|
||||
log_msg = 'Deleting keypairs: {0}'.format(keypair_list)
|
||||
self._log.info(log_msg)
|
||||
failed_deletes = []
|
||||
if keypair_list:
|
||||
for key in keypair_list:
|
||||
resp = self.compute.keypairs.client.delete_keypair(key.name)
|
||||
resp_check = self.check_response(
|
||||
resp=resp, status_code=ComputeResponseCodes.DELETE_KEYPAIR,
|
||||
label=key.name, message='Keypair DELETE failure')
|
||||
if resp_check and raise_exception:
|
||||
raise UnableToDeleteKeypair(resp_check)
|
||||
label=key.name, message='Keypair DELETE failure',
|
||||
entity_check=False)
|
||||
if resp_check:
|
||||
failed_deletes.append(resp_check)
|
||||
if raise_exception:
|
||||
raise UnableToDeleteKeypair(resp_check)
|
||||
|
||||
return failed_deletes
|
||||
|
||||
def wait_for_servers_to_be_active(self, server_id_list,
|
||||
interval_time=None, timeout=None,
|
||||
|
@ -564,26 +570,42 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
|||
if raise_exception:
|
||||
raise TimeoutException(msg)
|
||||
|
||||
def wait_for_servers_to_be_deleted(self, server_id_list,
|
||||
def wait_for_servers_to_be_deleted(self, server_id_list=None, name=None,
|
||||
interval_time=None, timeout=None,
|
||||
raise_exception=False):
|
||||
"""
|
||||
@summary: Waits for multiple servers to be deleted
|
||||
@param server_id_list: The uuids of the servers to be deleted
|
||||
@type server_id_list: List
|
||||
@param name: name or name_starts_with* to filter by
|
||||
@type name: str
|
||||
@param interval_time: Seconds to wait between polling
|
||||
@type interval_time: Integer
|
||||
@param timeout: The amount of time in seconds to wait before aborting
|
||||
@type timeout: Integer
|
||||
@param raise_exception: flag to raise an exception if delete fails
|
||||
@type raise_exception: bool
|
||||
"""
|
||||
|
||||
self._wait_for_compute_delete(
|
||||
if self.compute is None:
|
||||
raise UnavailableComputeInteractionException
|
||||
|
||||
if not server_id_list:
|
||||
if not name:
|
||||
raise MissingDataException('Missing name pattern')
|
||||
server_id_list = self.list_server_ids(name=name)
|
||||
log_msg = 'Deleting servers: {0}'.format(server_id_list)
|
||||
self._log.info(log_msg)
|
||||
|
||||
failed_deletes = self._wait_for_compute_delete(
|
||||
resource_id_list=server_id_list, resource='servers',
|
||||
delete_method=self.compute.servers.client.delete_server,
|
||||
get_method=self.compute.servers.client.get_server,
|
||||
interval_time=interval_time, timeout=timeout,
|
||||
raise_exception=raise_exception)
|
||||
|
||||
return failed_deletes
|
||||
|
||||
def _wait_for_compute_delete(self, resource_id_list, resource,
|
||||
delete_method, get_method, interval_time=None,
|
||||
timeout=None, raise_exception=False):
|
||||
|
@ -609,6 +631,7 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
|||
self.compute.servers.config.server_status_interval)
|
||||
timeout = timeout or self.compute.servers.config.server_build_timeout
|
||||
end_time = time.time() + timeout
|
||||
failed_deletes = []
|
||||
|
||||
for resource_id in resource_id_list:
|
||||
delete_method(resource_id)
|
||||
|
@ -619,19 +642,31 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
|||
if (resp.status_code == ComputeResponseCodes.NOT_FOUND and
|
||||
resource_id in resource_id_list):
|
||||
resource_id_list.remove(resource_id)
|
||||
|
||||
# Retrying to delete servers in ERROR status
|
||||
elif (hasattr(resp, 'entity') and
|
||||
hasattr(resp.entity, 'status') and
|
||||
resp.entity.status == ComputeStatus.ERROR):
|
||||
delete_method(resource_id)
|
||||
|
||||
if not resource_id_list:
|
||||
break
|
||||
time.sleep(interval_time)
|
||||
else:
|
||||
msg = ('Wait for compute {0} resource delete {0} seconds timeout '
|
||||
'for the expected resource get HTTP {1} status code for '
|
||||
'resources: {2}').format(resource, timeout,
|
||||
msg = ('Wait for compute {0} resource delete {1} seconds timeout '
|
||||
'for the expected resource get HTTP {2} status code for '
|
||||
'resources: {3}').format(resource, timeout,
|
||||
ComputeResponseCodes.NOT_FOUND,
|
||||
resource_id_list)
|
||||
self._log.info(msg)
|
||||
failed_deletes.append(msg)
|
||||
if raise_exception:
|
||||
raise TimeoutException(msg)
|
||||
|
||||
# keeping the response consistent with the _delete_resources of the
|
||||
# networking.networks.common.behaviors (failed_deletes)
|
||||
return failed_deletes
|
||||
|
||||
def create_multiple_servers(self, create_by='names', names=None,
|
||||
images=None, flavors=None,
|
||||
keypair_name=None, networks=None, ports=None,
|
||||
|
|
|
@ -48,7 +48,7 @@ class NetworkingBaseBehaviors(BaseBehavior):
|
|||
self.config = NetworkingBaseConfig()
|
||||
|
||||
def check_response(self, resp, status_code, label, message,
|
||||
network_id=None):
|
||||
network_id=None, entity_check=True):
|
||||
"""
|
||||
@summary: Checks the API response object
|
||||
@param resp: API call response object
|
||||
|
@ -61,6 +61,8 @@ class NetworkingBaseBehaviors(BaseBehavior):
|
|||
@type message: string
|
||||
@param network_id: related Network ID (optional)
|
||||
@type network_id: string
|
||||
@param entity_check: flag to enable/disable the response entity check
|
||||
@type entity_check: bool
|
||||
@return: None if the response is the expected or the error message
|
||||
@rtype: None or string
|
||||
"""
|
||||
|
@ -89,11 +91,13 @@ class NetworkingBaseBehaviors(BaseBehavior):
|
|||
expected_status=status_code)
|
||||
self._log.error(err_msg)
|
||||
response_msg = err_msg
|
||||
elif not resp.entity:
|
||||
elif not resp.entity and entity_check:
|
||||
err_msg = ('{label} {message}: Unable to get response'
|
||||
' entity object').format(label=label, message=message)
|
||||
self._log.error(err_msg)
|
||||
response_msg = err_msg
|
||||
elif not entity_check:
|
||||
response_msg = None
|
||||
else:
|
||||
|
||||
# This should NOT happen, scenarios should be covered by the elifs
|
||||
|
@ -159,6 +163,21 @@ class NetworkingBaseBehaviors(BaseBehavior):
|
|||
id_list = [entity.id for entity in entity_list]
|
||||
return id_list
|
||||
|
||||
def get_name_list_from_entity_list(self, entity_list, name=None):
|
||||
"""
|
||||
@summary: Gets a name list from an entity list
|
||||
@param entity_list: List of instances with the name and id attributes
|
||||
@type entity_list: list(instances)
|
||||
@param name: (optional) name or name_starts_with* to filter by
|
||||
@type name: str
|
||||
@return: name list
|
||||
@rtype: list
|
||||
"""
|
||||
if name:
|
||||
entity_list = self.filter_entity_list_by_name(entity_list, name)
|
||||
name_list = [entity.name for entity in entity_list]
|
||||
return name_list
|
||||
|
||||
def __over_limit_retry(self, resource_type, timeout, poll_interval,
|
||||
status_code, resp, fn_name, fn_kwargs):
|
||||
"""
|
||||
|
|
|
@ -13,6 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
|
||||
from cloudcafe.common.models.configuration import ConfigSectionInterface
|
||||
|
||||
|
||||
|
@ -115,3 +119,11 @@ class NetworkingBaseConfig(ConfigSectionInterface):
|
|||
def accepted_packet_loss(self):
|
||||
"""Accepted packet loss percent for server pings"""
|
||||
return int(self.get("accepted_packet_loss", 0))
|
||||
|
||||
@property
|
||||
def delete_resources(self):
|
||||
"""
|
||||
JSON string that may be used by the delete_networking resource_dict
|
||||
at: networking.networks.common.tools.resources
|
||||
"""
|
||||
return json.loads(self.get("delete_resources", '{}'))
|
||||
|
|
|
@ -115,7 +115,7 @@ class ComputeResponseCodes(object):
|
|||
CREATE_KEYPAIR = 200
|
||||
GET_KEYPAIR = 200
|
||||
LIST_KEYPAIRS = 200
|
||||
DELETE_KEYPAIR = 204
|
||||
DELETE_KEYPAIR = 202
|
||||
|
||||
|
||||
class ComputeStatus(NovaServerStatusTypes):
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
"""
|
||||
Copyright 2016 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
|
@ -0,0 +1,385 @@
|
|||
"""
|
||||
Copyright 2016 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import os
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
from cloudcafe.networking.networks.common.composites import CustomComposite
|
||||
from cloudcafe.networking.networks.common.exceptions \
|
||||
import MissingDataException
|
||||
|
||||
|
||||
class Resources(object):
|
||||
"""Networking resource management class for list and delete methods.
|
||||
|
||||
Attributes:
|
||||
resources (list): networking resources to manage, for ex.
|
||||
['servers', 'keypairs', 'security_groups',
|
||||
'ports', 'subnets', 'networks']
|
||||
all (str): name pattern to be used by all resources. Except for the
|
||||
resources attributes with value.
|
||||
servers (str): name pattern used for servers if given.
|
||||
keypairs (str): name pattern used for keypairs if given.
|
||||
networks (str): name pattern used for networks if given.
|
||||
subnets (str): name pattern used for subnets if given.
|
||||
ports (str): name pattern used for ports if given.
|
||||
security_groups (str): name pattern used for security groups if given.
|
||||
failed_servers (list): for tracking delete failures on delete calls.
|
||||
failed_keypairs (list): for tracking delete failures on delete calls.
|
||||
failed_networks (list): for tracking delete failures on delete calls.
|
||||
failed_subnets (list): for tracking delete failures on delete calls.
|
||||
failed_ports (list): for tracking delete failures on delete calls.
|
||||
failed_security_groups (list): for tracking delete failures on delete.
|
||||
|
||||
The class attributes are set after the set_resources call.
|
||||
"""
|
||||
|
||||
# Key names for resources composite behaviors object and get/delete methods
|
||||
RES_COM = 'res_com'
|
||||
GET_FN = 'get_fn'
|
||||
DEL_FN = 'del_fn'
|
||||
|
||||
def __init__(self):
|
||||
self.resources = None
|
||||
|
||||
def set_resources(self, resources, initial_val=None):
|
||||
"""Setting resource values and failed list as class attributes
|
||||
|
||||
Args:
|
||||
resources (list): resources list for ex.
|
||||
['servers', 'networks', ...]
|
||||
"""
|
||||
|
||||
self.resources = resources
|
||||
|
||||
# Initialize the resources as class attributes with None
|
||||
# And the resource delete lists as empty lists
|
||||
self.set_resources_val(initial_val)
|
||||
self.set_failed_deletes()
|
||||
|
||||
def set_resources_val(self, val):
|
||||
"""Setting attribute values to capture resource info
|
||||
|
||||
Args:
|
||||
val(str): values of class attributes listed in self.resources
|
||||
"""
|
||||
|
||||
for resource in self.resources:
|
||||
setattr(self, resource, val)
|
||||
|
||||
def set_failed_deletes(self):
|
||||
"""Resetting attribute lists to track resource failed deletes"""
|
||||
|
||||
for resource in self.resources:
|
||||
delete_list = 'failed_{0}'.format(resource)
|
||||
setattr(self, delete_list, list())
|
||||
|
||||
def get_config_file(self, file_path=None):
|
||||
"""Getting the config file
|
||||
|
||||
Args:
|
||||
file_path(Optional[str]): config file path
|
||||
"""
|
||||
|
||||
if not file_path:
|
||||
file_path = os.environ.get('CAFE_CONFIG_FILE_PATH')
|
||||
if not file_path:
|
||||
msg = ('The file_path must be given or the environment '
|
||||
'variable CAFE_CONFIG_FILE_PATH must be set')
|
||||
raise MissingDataException(msg)
|
||||
|
||||
if not file_path.endswith('.config'):
|
||||
config_file = ''.join([file_path, '.config'])
|
||||
else:
|
||||
config_file = file_path
|
||||
return config_file
|
||||
|
||||
def list_networking(self, name=None, file_path=None, verbose=True,
|
||||
resource_show=None, resource_filter=None,
|
||||
raise_exception=False):
|
||||
"""Get method for networking related resources
|
||||
|
||||
Args:
|
||||
name (Optional[str]): name pattern to filter by responses.
|
||||
If not given all resources will be listed.
|
||||
file_path (Optional[str]): config directory path with file name
|
||||
(the .config extension may be omitted). If not given the
|
||||
CAFE_CONFIG_FILE_PATH environment variable value will be used.
|
||||
verbose (Optional[bool]): flag to print delete msgs to console.
|
||||
resource_show (Optional[list]): resources to show only.
|
||||
resource_filter (Optional[list]): resources to skip showing.
|
||||
Ignored if resource_show given.
|
||||
raise_exception (Optional [bool]): flag for raising an exception
|
||||
if get calls throw an error.
|
||||
|
||||
Returns:
|
||||
dict: ONLY if verbose is set to False, otherwise this info
|
||||
is printed by the method call. The names and id counts by
|
||||
resource are returned as well as a list of them on a table.
|
||||
|
||||
For ex.
|
||||
{'subnets': {'table': <prettytable.PrettyTable object>
|
||||
'names': 2, 'ids': 2},
|
||||
'keypairs': {'table': <prettytable.PrettyTable object>,
|
||||
'names': 0, 'ids': 0},
|
||||
'networks': {'table': <prettytable.PrettyTable object>,
|
||||
'names': 2, 'ids': 2},
|
||||
'ports': {'table': <prettytable.PrettyTable object,
|
||||
'names': 0, 'ids': 0},
|
||||
'security_groups': {'table': <prettytable.PrettyTable object>,
|
||||
'names': 0, 'ids': 0},
|
||||
'servers': {'table': <prettytable.PrettyTable object>,
|
||||
'names': 3, 'ids': 3}}
|
||||
"""
|
||||
|
||||
config_file = self.get_config_file(file_path=file_path)
|
||||
|
||||
if verbose:
|
||||
print 'Using config file {0}'.format(config_file)
|
||||
|
||||
# Setting the custom composite
|
||||
com = CustomComposite(config_file_path=config_file)
|
||||
com.set_cafe_config_file_path()
|
||||
com.set_cafe_composites()
|
||||
|
||||
# Defining resources get calls.
|
||||
res_fn = collections.OrderedDict([
|
||||
('servers', {self.RES_COM: com.net.behaviors,
|
||||
self.GET_FN: 'list_servers'}),
|
||||
('keypairs', {self.RES_COM: com.net.behaviors,
|
||||
self.GET_FN: 'list_keypairs'}),
|
||||
('security_groups', {self.RES_COM: com.sec.behaviors,
|
||||
self.GET_FN: 'list_security_groups'}),
|
||||
('ports', {self.RES_COM: com.ports.behaviors,
|
||||
self.GET_FN: 'list_ports'}),
|
||||
('subnets', {self.RES_COM: com.subnets.behaviors,
|
||||
self.GET_FN: 'list_subnets'}),
|
||||
('networks', {self.RES_COM: com.networks.behaviors,
|
||||
self.GET_FN: 'list_networks'})
|
||||
])
|
||||
|
||||
resources = res_fn.keys()
|
||||
resources_count = dict()
|
||||
|
||||
resource_set = set(resources)
|
||||
if resource_show:
|
||||
resources = list(resource_set.intersection(resource_show))
|
||||
elif resource_filter:
|
||||
resource_filter = list(resource_set.intersection(resource_filter))
|
||||
filter(resources.remove, resource_filter)
|
||||
|
||||
output_list = []
|
||||
for resource in resources:
|
||||
resource_table = PrettyTable()
|
||||
count = dict()
|
||||
res_com = res_fn[resource][self.RES_COM]
|
||||
get_fn = res_fn[resource][self.GET_FN]
|
||||
params_kwargs = dict(raise_exception=raise_exception)
|
||||
|
||||
resp = getattr(res_com, get_fn)(**params_kwargs)
|
||||
|
||||
# Extracting the nested requests response object in networking
|
||||
# resources. This is not needed for the compute resources.
|
||||
if resource in ['networks', 'subnets', 'ports', 'security_groups']:
|
||||
resp = resp.response.entity
|
||||
|
||||
name_list = res_com.get_name_list_from_entity_list(
|
||||
entity_list=resp, name=name)
|
||||
resource_name = '{0}_name'.format(resource)
|
||||
resource_table.add_column(resource_name, name_list)
|
||||
names_count = len(name_list)
|
||||
count.update({'names': names_count})
|
||||
|
||||
# For resources without ids like Keypairs
|
||||
if resource not in ['keypairs']:
|
||||
id_list = res_com.get_id_list_from_entity_list(
|
||||
entity_list=resp, name=name)
|
||||
resource_id = '{0}_id'.format(resource)
|
||||
resource_table.add_column(resource_id, id_list)
|
||||
else:
|
||||
id_list = []
|
||||
ids_count = len(id_list)
|
||||
count.update({'ids': ids_count})
|
||||
|
||||
resource_table.align = 'l'
|
||||
|
||||
output_list.append(resource_table)
|
||||
count.update({'table': resource_table})
|
||||
resources_count.update({resource: count})
|
||||
|
||||
if verbose:
|
||||
print resource_table
|
||||
|
||||
if verbose:
|
||||
print 'Resources Summary'
|
||||
for k, v in resources_count.items():
|
||||
report = '{0}: {1} with name and {2} with id'.format(
|
||||
k, v['names'], v['ids'])
|
||||
print report
|
||||
note = ('NOTE: Some resources like ports, may have an empty string'
|
||||
' as name. Others, like keypairs, may not have id')
|
||||
print note
|
||||
else:
|
||||
# This is jut in case the printing is desired to be done elsewhere
|
||||
return resources_count
|
||||
|
||||
def delete_networking(self, file_path=None, resource_dict=None,
|
||||
timeout=None, raise_exception=None, verbose=True):
|
||||
"""Clean up method for networking related resources
|
||||
|
||||
Args:
|
||||
file_path (Optional[str]): config directory path with file name
|
||||
(the .config extension may be omitted). If not given the
|
||||
CAFE_CONFIG_FILE_PATH environment variable value will be used.
|
||||
resource_dict (Optional[dict]): Resource names to be used for
|
||||
deletion, all possible keys are,
|
||||
{'all': 'test*', 'servers': 'test_svr*', 'keypairs': 'test*',
|
||||
'security_group_rules': 'test*', 'security_groups': 'test*',
|
||||
'ports': 'ports*', 'subnets': 'test*', 'networks': 'test*'}
|
||||
|
||||
The values here are just name pattern examples and should be
|
||||
set to '*' for all or may have a resource start name like
|
||||
'test*', that will delete all resources starting with test
|
||||
on their name. You can also give a resource exact name, or
|
||||
an non matching pattern name to skip resource deletions.
|
||||
|
||||
If the all key is given, all resources will be targeted for
|
||||
deletion with its value as the name pattern to be used.
|
||||
If other resource keys are given, in combination with the all
|
||||
key, these resource values will be used for their name pattern.
|
||||
|
||||
If the all key is not given, only resource given keys will be
|
||||
targeted for deletion.
|
||||
|
||||
If the resource dict is not given at all, the default value
|
||||
will be {'all': '*'} that will delete ALL resources.
|
||||
|
||||
timeout (Optional[int]): wait time for server deletion. If not
|
||||
given default val compute.servers.config.server_build_timeout
|
||||
raise_exception (Optional [bool]): flag for raising an exception
|
||||
if servers aren't deleted within the timeout.
|
||||
verbose (Optional[bool]): flag to print delete msgs to console.
|
||||
"""
|
||||
|
||||
# Defining initial values
|
||||
config_file = self.get_config_file(file_path=file_path)
|
||||
|
||||
if verbose:
|
||||
print 'Using config file {0}'.format(config_file)
|
||||
|
||||
if not resource_dict:
|
||||
resource_dict = {'all': '*'}
|
||||
|
||||
# Setting the custom composite
|
||||
com = CustomComposite(config_file_path=config_file)
|
||||
com.set_cafe_config_file_path()
|
||||
com.set_cafe_composites()
|
||||
|
||||
# Defining resources delete calls. Delete order is important.
|
||||
res_fn = collections.OrderedDict([
|
||||
('servers', {self.RES_COM: com.net.behaviors,
|
||||
self.DEL_FN: 'wait_for_servers_to_be_deleted'}),
|
||||
('keypairs', {self.RES_COM: com.net.behaviors,
|
||||
self.DEL_FN: 'delete_keypairs'}),
|
||||
('security_groups', {self.RES_COM: com.sec.behaviors,
|
||||
self.DEL_FN: 'delete_security_groups'}),
|
||||
('ports', {self.RES_COM: com.ports.behaviors,
|
||||
self.DEL_FN: 'delete_ports'}),
|
||||
('subnets', {self.RES_COM: com.subnets.behaviors,
|
||||
self.DEL_FN: 'delete_subnets'}),
|
||||
('networks', {self.RES_COM: com.networks.behaviors,
|
||||
self.DEL_FN: 'delete_networks'})
|
||||
])
|
||||
|
||||
resources = res_fn.keys()
|
||||
|
||||
# Getting the name value for all resources if given
|
||||
all_resources = resource_dict.get('all')
|
||||
|
||||
# Setting the resources as class attrs with initial name value
|
||||
self.set_resources(resources=resources, initial_val=all_resources)
|
||||
|
||||
# Overwriting individual resource name value if given
|
||||
for k, v in resource_dict.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
for resource in resources:
|
||||
# Getting resources name patterns from class attrs
|
||||
name_pattern = getattr(self, resource)
|
||||
|
||||
if name_pattern:
|
||||
|
||||
if verbose:
|
||||
msg = 'Deleting {0} with name: {1}'.format(resource,
|
||||
name_pattern)
|
||||
if resource == 'servers':
|
||||
if timeout:
|
||||
timeout_val = timeout
|
||||
else:
|
||||
timeout_val = (
|
||||
'compute.servers.config.server_build_timeout')
|
||||
add_msg = 'Within timeout: {0}'.format(timeout_val)
|
||||
msg = '\n'.join([msg, add_msg])
|
||||
print msg
|
||||
|
||||
res_com = res_fn[resource][self.RES_COM]
|
||||
del_fn = res_fn[resource][self.DEL_FN]
|
||||
params_kwargs = dict(name=name_pattern)
|
||||
|
||||
if resource == 'servers':
|
||||
add_params = dict(timeout=timeout,
|
||||
raise_exception=raise_exception)
|
||||
params_kwargs.update(add_params)
|
||||
|
||||
failed_deletes = getattr(res_com, del_fn)(**params_kwargs)
|
||||
|
||||
if verbose and failed_deletes:
|
||||
msg = '\nUnable to delete the following {0}'.format(
|
||||
resource)
|
||||
print msg
|
||||
|
||||
for failure in failed_deletes:
|
||||
print failure
|
||||
|
||||
# Updating resource failure list in res object
|
||||
failed_name = 'failed_{0}'.format(resource)
|
||||
setattr(self, failed_name, failed_deletes)
|
||||
|
||||
if verbose:
|
||||
print '\n'
|
||||
print '*'*9
|
||||
print 'Delete resource summary'
|
||||
print '"*" implies names starts with'
|
||||
print 'Resources list are all available resource options'
|
||||
print 'Failed lists populated with failures if any\n'
|
||||
print self
|
||||
print '*'*9
|
||||
|
||||
def __repr__(self):
|
||||
"""Representing resource attributes: str, int and list"""
|
||||
data = self.__dict__
|
||||
msg = ['Resources']
|
||||
for key, value in data.items():
|
||||
val_type = type(value)
|
||||
if val_type is str or val_type is int or val_type is list:
|
||||
s = '{0}: {1}'.format(key, value)
|
||||
msg.append(s)
|
||||
if len(msg) < 2:
|
||||
msg.append('No resources have been set')
|
||||
res = '\n'.join(msg)
|
||||
return res
|
Loading…
Reference in New Issue