diff --git a/cloudcafe/compute/common/types.py b/cloudcafe/compute/common/types.py index f65d0f01..48db2204 100644 --- a/cloudcafe/compute/common/types.py +++ b/cloudcafe/compute/common/types.py @@ -42,6 +42,55 @@ class NovaServerStatusTypes(object): PAUSED = "PAUSED" +class ComputeTaskStates(object): + NONE = 'none' + + # Basic server lifecycle + SCHEDULING = 'scheduling' + SPAWNING = 'spawning' + BLOCK_DEVICE_MAPPING = 'block_device_mapping' + DELETING = 'deleting' + SOFT_DELETING = 'soft-deleting' + RESTORING = 'restoring' + SHELVING = 'shelving' + SHELVING_IMAGE_PENDING_UPLOAD = 'shelving_image_pending_upload' + SHELVING_IMAGE_UPLOADING = 'shelving_image_uploading' + SHELVING_OFFLOADING = 'shelving_offloading' + UNSHELVING = 'unshelving' + + # Server Actions + REBUILDING = 'rebuilding' + REBUILD_BLOCK_DEVICE_MAPPING = 'rebuild_block_device_mapping' + REBUILD_SPAWNING = 'rebuild_spawning' + RESIZE_PREP = 'resize_prep' + RESIZE_MIGRATING = 'resize_migrating' + RESIZE_MIGRATED = 'resize_migrated' + RESIZE_FINISH = 'resize_finish' + RESIZE_REVERTING = 'resize_reverting' + RESIZE_CONFIRMING = 'resize_confirming' + RESCUING = 'rescuing' + UNRESCUING = 'unrescuing' + UPDATING_PASSWORD = 'updating_password' + PAUSING = 'pausing' + UNPAUSING = 'unpausing' + SUSPENDING = 'suspending' + RESUMING = 'resuming' + STOPPING = 'stopping' + STARTING = 'starting' + POWERING_OFF = 'powering-off' + POWERING_ON = 'powering-on' + MIGRATING = 'migrating' + REBOOTING = 'rebooting' + REBOOTING_HARD = 'rebooting_hard' + + # Imaging + IMAGE_SNAPSHOT = 'image_snapshot' + IMAGE_PENDING_UPLOAD = 'image_pending_upload' + IMAGE_UPLOADING = 'image_uploading' + IMAGE_BACKUP = 'image_backup' + IMAGE_LIVE_SNAPSHOT = 'image_live_snapshot' + + class NovaImageStatusTypes(object): """ @summary: Types dictating an individual Server Status diff --git a/cloudcafe/compute/servers_api/client.py b/cloudcafe/compute/servers_api/client.py index cc7cacf8..9136550e 100644 --- a/cloudcafe/compute/servers_api/client.py +++ b/cloudcafe/compute/servers_api/client.py @@ -20,7 +20,8 @@ from cloudcafe.compute.common.models.metadata import Metadata from cloudcafe.compute.common.models.metadata import MetadataItem from cloudcafe.compute.extensions.security_groups_api.models.security_group \ import SecurityGroups, SecurityGroup -from cloudcafe.compute.servers_api.models.servers import Server +from cloudcafe.compute.servers_api.models.servers import Server, Servers, \ + ServerMins from cloudcafe.compute.servers_api.models.servers import Addresses from cloudcafe.compute.servers_api.models.servers import InstanceActions from cloudcafe.compute.servers_api.models.requests import CreateServer, \ @@ -89,7 +90,7 @@ class ServersClient(AutoMarshallingRestClient): 'limit': limit, 'changes-since': changes_since} url = '{base_url}/servers'.format(base_url=self.url) resp = self.request('GET', url, params=params, - response_entity_type=Server, + response_entity_type=ServerMins, requestslib_kwargs=requestslib_kwargs) return resp @@ -123,7 +124,7 @@ class ServersClient(AutoMarshallingRestClient): 'changes-since': changes_since} url = '{base_url}/servers/detail'.format(base_url=self.url) resp = self.request('GET', url, params=params, - response_entity_type=Server, + response_entity_type=Servers, requestslib_kwargs=requestslib_kwargs) return resp diff --git a/cloudcafe/compute/servers_api/models/servers.py b/cloudcafe/compute/servers_api/models/servers.py index 21aaa209..338678ae 100644 --- a/cloudcafe/compute/servers_api/models/servers.py +++ b/cloudcafe/compute/servers_api/models/servers.py @@ -16,36 +16,38 @@ limitations under the License. import IPy import json -import re import xml.etree.ElementTree as ET +from cafe.engine.models.base import AutoMarshallingModel, \ + AutoMarshallingListModel from cafe.engine.models.base import BaseModel -from cafe.engine.models.base import AutoMarshallingModel +from cloudcafe.compute.common.constants import Constants +from cloudcafe.compute.common.types import ComputeTaskStates +from cloudcafe.compute.common.equality_tools import EqualityTools from cloudcafe.compute.common.models.link import Links +from cloudcafe.compute.common.models.metadata import Metadata from cloudcafe.compute.flavors_api.models.flavor import Flavor, FlavorMin from cloudcafe.compute.images_api.models.image import Image, ImageMin -from cloudcafe.compute.common.equality_tools import EqualityTools -from cloudcafe.compute.common.constants import Constants -from cloudcafe.compute.common.models.metadata import Metadata class Server(AutoMarshallingModel): - def __init__(self, id=None, disk_config=None, config_drive=None, - power_state=None, progress=None, task_state=None, - vm_state=None, name=None, tenant_id=None, status=None, - updated=None, created=None, host_id=None, user_id=None, - accessIPv4=None, accessIPv6=None, addresses=None, - flavor=None, image=None, links=None, metadata=None, - admin_pass=None, key_name=None): - self.diskConfig = disk_config + def __init__(self, id=None, disk_config=None, power_state=None, + progress=None, task_state=None, vm_state=None, name=None, + tenant_id=None, status=None, updated=None, created=None, + host_id=None, user_id=None, accessIPv4=None, accessIPv6=None, + addresses=None, flavor=None, image=None, links=None, + metadata=None, admin_pass=None, key_name=None, + config_drive=None): + super(Server, self).__init__() + self.disk_config = disk_config self.config_drive = config_drive try: self.power_state = int(power_state) except TypeError: self.power_state = 0 self.progress = progress - self.task_state = task_state + self.task_state = task_state or ComputeTaskStates.NONE self.vm_state = vm_state self.name = name self.id = id @@ -59,12 +61,10 @@ class Server(AutoMarshallingModel): self.accessIPv4 = str(IPy.IP(accessIPv4)) else: self.accessIPv4 = None - if accessIPv6: self.accessIPv6 = str(IPy.IP(accessIPv6)) else: self.accessIPv6 = None - self.addresses = addresses self.flavor = flavor self.image = image @@ -75,27 +75,12 @@ class Server(AutoMarshallingModel): @classmethod def _json_to_obj(cls, serialized_str): - ''' - Returns an instance of a Server based on the json serialized_str - passed in - ''' - ret = None json_dict = json.loads(serialized_str) - if 'server' in json_dict.keys(): - ret = cls._dict_to_obj(json_dict['server']) - if 'servers' in json_dict.keys(): - ret = [] - for server in json_dict['servers']: - s = cls._dict_to_obj(server) - ret.append(s) + ret = cls._dict_to_obj(json_dict['server']) return ret @classmethod def _xml_to_obj(cls, serialized_str): - ''' - Returns an instance of a Server based on the xml serialized_str - passed in - ''' element = ET.fromstring(serialized_str) cls._remove_xml_etree_namespace( element, Constants.XML_API_NAMESPACE) @@ -105,18 +90,11 @@ class Server(AutoMarshallingModel): element, Constants.XML_API_DISK_CONFIG_NAMESPACE) cls._remove_xml_etree_namespace( element, Constants.XML_API_ATOM_NAMESPACE) - if element.tag == 'server': - ret = cls._xml_ele_to_obj(element) - if element.tag == 'servers': - ret = [] - for server in element.findall('server'): - s = cls._xml_ele_to_obj(server) - ret.append(s) + ret = cls._xml_ele_to_obj(element) return ret @classmethod def _xml_ele_to_obj(cls, element): - '''Helper method to turn ElementTree instance to Server instance.''' server = element.attrib addresses = None @@ -135,19 +113,19 @@ class Server(AutoMarshallingModel): metadata = Metadata._xml_ele_to_obj(element.find('metadata')) if 'progress' in server: - progress = server.get('progress') \ - and int(server.get('progress')) + progress = (server.get('progress') + and int(server.get('progress'))) else: progress = None server = Server( id=server.get('id'), disk_config=server.get('diskConfig'), power_state=server.get('power_state'), progress=progress, - task_state=server.get('task_state'), + task_state=server.get('task_state').lower(), vm_state=server.get('vm_state'), name=server.get('name'), - tenant_id=server.get('tenant_id'), status=server.get('status'), + tenant_id=server.get('tenantId'), status=server.get('status'), updated=server.get('updated'), created=server.get('created'), - host_id=server.get('hostId'), user_id=server.get('user_id'), + host_id=server.get('hostId'), user_id=server.get('userId'), accessIPv4=server.get('accessIPv4'), config_drive=server.get('config_drive'), accessIPv6=server.get('accessIPv6'), addresses=addresses, @@ -159,7 +137,6 @@ class Server(AutoMarshallingModel): @classmethod def _dict_to_obj(cls, server_dict): - '''Helper method to turn dictionary into Server instance.''' addresses = None flavor = None @@ -202,92 +179,82 @@ class Server(AutoMarshallingModel): return server def __eq__(self, other): - """ - @summary: Overrides the default equals - @param other: Server object to compare with - @type other: Server - @return: True if Server objects are equal, False otherwise - @rtype: bool - """ return EqualityTools.are_objects_equal(self, other, ['admin_pass', 'updated', 'progress']) def __ne__(self, other): - """ - @summary: Overrides the default not-equals - @param other: Server object to compare with - @type other: Server - @return: True if Server objects are not equal, False otherwise - @rtype: bool - """ return not self == other def min_details(self): - """ - @summary: Get the Minimum details of server - @return: Minimum details of server - @rtype: ServerMin - """ return ServerMin(name=self.name, id=self.id, links=self.links) class ServerMin(Server): - """ - @summary: Represents minimum details of a server - """ - def __init__(self, **kwargs): - for keys, values in kwargs.items(): - setattr(self, keys, values) + + def __init__(self, id=None, name=None, links=None): + super(ServerMin, self).__init__() + self.id = id + self.name = name + self.links = links def __eq__(self, other): - """ - @summary: Overrides the default equals - @param other: ServerMin object to compare with - @type other: ServerMin - @return: True if ServerMin objects are equal, False otherwise - @rtype: bool - """ return EqualityTools.are_objects_equal(self, other) def __ne__(self, other): - """ - @summary: Overrides the default equals - @param other: ServerMin object to compare with - @type other: ServerMin - @return: True if ServerMin objects are not equal, False otherwise - @rtype: bool - """ return not self == other @classmethod def _xml_ele_to_obj(cls, element): - '''Helper method to turn ElementTree instance to Server instance.''' - if element.find('server') is not None: - element = element.find('server') - server_dict = element.attrib - servermin = ServerMin(**server_dict) - servermin.links = Links._xml_ele_to_obj(element) - return servermin + server_dict = element.attrib + links = Links._xml_ele_to_obj(element) + server = ServerMin(id=server_dict.get('id'), + name=server_dict.get('name'), links=links) + return server @classmethod def _dict_to_obj(cls, server_dict): - '''Helper method to turn dictionary into Server instance.''' - servermin = ServerMin(**server_dict) - if hasattr(servermin, 'links'): - servermin.links = Links._dict_to_obj(servermin.links) - ''' - Parse for those keys which have the namespace prefixed, - strip the namespace out - and take only the actual values such as diskConfig, - power_state and assign to server obj - ''' - for each in server_dict: - if each.startswith("{"): - newkey = re.split("}", each)[1] - setattr(servermin, newkey, server_dict[each]) + links = Links._dict_to_obj(server_dict['links']) + server = ServerMin(id=server_dict.get('id'), + name=server_dict.get('name'), links=links) + return server - return servermin + +class Servers(AutoMarshallingListModel): + + server_type = Server + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = json.loads(serialized_str) + return cls._list_to_obj(json_dict.get('servers')) + + @classmethod + def _list_to_obj(cls, server_dict_list): + servers = Servers() + for server_dict in server_dict_list: + server = cls.server_type._dict_to_obj(server_dict) + servers.append(server) + return servers + + @classmethod + def _xml_to_obj(cls, serialized_str): + element = ET.fromstring(serialized_str) + if element.tag != 'servers': + return None + return cls._xml_list_to_obj(element.findall('server')) + + @classmethod + def _xml_list_to_obj(cls, xml_list): + servers = Servers() + for ele in xml_list: + servers.append(cls.server_type._xml_ele_to_obj(ele)) + return servers + + +class ServerMins(Servers): + + server_type = ServerMin class Addresses(AutoMarshallingModel): diff --git a/metatests/cloudcafe/compute/servers/models/test_servers.py b/metatests/cloudcafe/compute/servers/models/test_servers.py index 5a5ce000..d27473ee 100644 --- a/metatests/cloudcafe/compute/servers/models/test_servers.py +++ b/metatests/cloudcafe/compute/servers/models/test_servers.py @@ -16,6 +16,7 @@ limitations under the License. import unittest2 as unittest +from cloudcafe.compute.common.types import ComputeTaskStates from cloudcafe.compute.servers_api.models.servers import Server @@ -31,7 +32,7 @@ class ServerDomainTest(object): self.assertEqual(self.server.progress, 100) def test_server_task_state(self): - self.assertEqual(self.server.task_state, None) + self.assertEqual(self.server.task_state, ComputeTaskStates.NONE) def test_server_vm_state(self): self.assertEqual(self.server.vm_state, "active")