[Libcloud-589] Add a new compute driver for ProfitBricks provider. Closes #352
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/34cff301 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/34cff301 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/34cff301 Branch: refs/heads/trunk Commit: 34cff3012c097b1f37b821bea60eb2c761d4fe15 Parents: 6869ebc Author: Matt Baldwin <[email protected]> Authored: Tue Aug 26 13:59:37 2014 -0700 Committer: Tomaz Muraus <[email protected]> Committed: Sun Sep 14 13:20:13 2014 +0200 ---------------------------------------------------------------------- CHANGES.rst | 4 + libcloud/compute/drivers/profitbricks.py | 1485 ++++++++++++++++++ libcloud/compute/providers.py | 2 + libcloud/compute/types.py | 2 + .../fixtures/profitbricks/attach_volume.xml | 12 + .../fixtures/profitbricks/create_node.xml | 13 + .../fixtures/profitbricks/create_volume.xml | 13 + .../fixtures/profitbricks/destroy_node.xml | 12 + .../fixtures/profitbricks/destroy_volume.xml | 12 + .../fixtures/profitbricks/detach_volume.xml | 12 + .../profitbricks/ex_clear_datacenter.xml | 12 + .../profitbricks/ex_create_datacenter.xml | 13 + .../ex_create_network_interface.xml | 13 + .../profitbricks/ex_describe_datacenter.xml | 15 + .../ex_describe_network_interface.xml | 26 + .../fixtures/profitbricks/ex_describe_node.xml | 77 + .../profitbricks/ex_describe_volume.xml | 22 + .../profitbricks/ex_destroy_datacenter.xml | 10 + .../ex_destroy_network_interface.xml | 12 + .../profitbricks/ex_list_datacenters.xml | 19 + .../profitbricks/ex_list_network_interfaces.xml | 75 + .../fixtures/profitbricks/ex_start_node.xml | 10 + .../fixtures/profitbricks/ex_stop_node.xml | 10 + .../profitbricks/ex_update_datacenter.xml | 12 + .../ex_update_network_interface.xml | 12 + .../fixtures/profitbricks/ex_update_node.xml | 12 + .../fixtures/profitbricks/ex_update_volume.xml | 12 + .../fixtures/profitbricks/list_images.xml | 43 + .../fixtures/profitbricks/list_nodes.xml | 172 ++ .../fixtures/profitbricks/list_volumes.xml | 66 + .../fixtures/profitbricks/reboot_node.xml | 10 + libcloud/test/compute/test_profitbricks.py | 509 ++++++ libcloud/test/secrets.py-dist | 1 + 33 files changed, 2730 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/CHANGES.rst ---------------------------------------------------------------------- diff --git a/CHANGES.rst b/CHANGES.rst index 1495ea7..e9ac0fd 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -98,6 +98,10 @@ Compute Reported by Xavier Barbosa. [Tomaz Muraus, Xavier Barbosa] +- Add new driver for ProfitBricks provider. + (LIBCLOUD-589, GITHUB-352) + [Matt Baldwin] + Storage ~~~~~~~ http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/compute/drivers/profitbricks.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/profitbricks.py b/libcloud/compute/drivers/profitbricks.py new file mode 100644 index 0000000..0d4a5ea --- /dev/null +++ b/libcloud/compute/drivers/profitbricks.py @@ -0,0 +1,1485 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +"""ProfitBricks Compute driver +""" +import base64 + +import copy +import time + +try: + from lxml import etree as ET +except ImportError: + from xml.etree import ElementTree as ET + +from libcloud.utils.networking import is_private_subnet +from libcloud.utils.py3 import b +from libcloud.compute.providers import Provider +from libcloud.common.base import ConnectionUserAndKey, XmlResponse +from libcloud.compute.base import Node, NodeDriver, NodeLocation, NodeSize +from libcloud.compute.base import NodeImage, StorageVolume +from libcloud.compute.base import UuidMixin +from libcloud.compute.types import NodeState +from libcloud.common.types import LibcloudError, MalformedResponseError + +__all__ = [ + 'API_VERSION', + 'API_HOST', + 'ProfitBricksNodeDriver', + 'Datacenter', + 'ProfitBricksNetworkInterface', + 'ProfitBricksAvailabilityZone' +] + +API_HOST = 'api.profitbricks.com' +API_VERSION = '/1.3/' + + +class ProfitBricksResponse(XmlResponse): + """ + ProfitBricks response parsing. + """ + def parse_error(self): + try: + body = ET.XML(self.body) + except: + raise MalformedResponseError('Failed to parse XML', + body=self.body, + driver=ProfitBricksNodeDriver) + + for e in body.findall('.//detail'): + if ET.iselement(e[0].find('httpCode')): + http_code = e[0].find('httpCode').text + else: + http_code = None + if ET.iselement(e[0].find('faultCode')): + fault_code = e[0].find('faultCode').text + else: + fault_code = None + if ET.iselement(e[0].find('message')): + message = e[0].find('message').text + else: + message = None + + return LibcloudError('HTTP Code: %s, Fault Code: %s, Message: %s' % + (http_code, fault_code, message), driver=self) + + +class ProfitBricksConnection(ConnectionUserAndKey): + """ + Represents a single connection to the ProfitBricks endpoint. + """ + host = API_HOST + api_prefix = API_VERSION + responseCls = ProfitBricksResponse + + def add_default_headers(self, headers): + headers['Content-Type'] = 'text/xml' + headers['Authorization'] = 'Basic %s' % (base64.b64encode( + b('%s:%s' % (self.user_id, self.key))).decode('utf-8')) + + return headers + + def encode_data(self, data): + soap_env = ET.Element('soapenv:Envelope', { + 'xmlns:soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:ws': 'http://ws.api.profitbricks.com/' + }) + ET.SubElement(soap_env, 'soapenv:Header') + soap_body = ET.SubElement(soap_env, 'soapenv:Body') + soap_req_body = ET.SubElement(soap_body, 'ws:%s' % (data['action'])) + + if 'request' in data.keys(): + soap_req_body = ET.SubElement(soap_req_body, 'request') + for key, value in data.items(): + if key not in ['action', 'request']: + child = ET.SubElement(soap_req_body, key) + child.text = value + else: + for key, value in data.items(): + if key != 'action': + child = ET.SubElement(soap_req_body, key) + child.text = value + + soap_post = ET.tostring(soap_env) + + return soap_post + + def request(self, action, params=None, data=None, headers=None, + method='POST', raw=False): + action = self.api_prefix + action + + return super(ProfitBricksConnection, self).request(action=action, + params=params, + data=data, + headers=headers, + method=method, + raw=raw) + + +class Datacenter(UuidMixin): + """ + Class which stores information about ProfitBricks datacenter + instances. + + :param id: The datacenter ID. + :type id: ``str`` + + :param name: The datacenter name. + :type name: ``str`` + + :param version: Datacenter version. + :type version: ``str`` + + + Note: This class is ProfitBricks specific. + """ + def __init__(self, id, name, version, driver, extra=None): + self.id = str(id) + self.name = name + self.version = version + self.driver = driver + self.extra = extra or {} + UuidMixin.__init__(self) + + def __repr__(self): + return (( + '<Datacenter: id=%s, name=%s, version=%s, driver=%s> ...>') + % (self.id, self.name, self.version, + self.driver.name)) + + +class ProfitBricksNetworkInterface(object): + """ + Class which stores information about ProfitBricks network + interfaces. + + :param id: The network interface ID. + :type id: ``str`` + + :param name: The network interface name. + :type name: ``str`` + + :param state: The network interface name. + :type state: ``int`` + + Note: This class is ProfitBricks specific. + """ + def __init__(self, id, name, state, extra=None): + self.id = id + self.name = name + self.state = state + self.extra = extra or {} + + def __repr__(self): + return (('<ProfitBricksNetworkInterface: id=%s, name=%s>') + % (self.id, self.name)) + + +class ProfitBricksAvailabilityZone(object): + """ + Extension class which stores information about a ProfitBricks + availability zone. + + Note: This class is ProfitBricks specific. + """ + + def __init__(self, name): + self.name = name + + def __repr__(self): + return (('<ProfitBricksAvailabilityZone: name=%s>') + % (self.name)) + + +class ProfitBricksNodeDriver(NodeDriver): + """ + Base ProfitBricks node driver. + """ + connectionCls = ProfitBricksConnection + name = 'ProfitBricks' + website = 'http://www.profitbricks.com' + type = Provider.PROFIT_BRICKS + + PROVISIONING_STATE = { + 'INACTIVE': NodeState.PENDING, + 'INPROCESS': NodeState.PENDING, + 'AVAILABLE': NodeState.RUNNING, + 'DELETED': NodeState.TERMINATED, + } + + NODE_STATE_MAP = { + 'NOSTATE': NodeState.UNKNOWN, + 'RUNNING': NodeState.RUNNING, + 'BLOCKED': NodeState.STOPPED, + 'PAUSE': NodeState.STOPPED, + 'SHUTDOWN': NodeState.PENDING, + 'SHUTOFF': NodeState.STOPPED, + 'CRASHED': NodeState.STOPPED, + } + + REGIONS = { + '1': {'region': 'us/las', 'country': 'USA'}, + '2': {'region': 'de/fra', 'country': 'DEU'}, + '3': {'region': 'de/fkb', 'country': 'DEU'}, + } + + AVAILABILITY_ZONE = { + '1': {'name': 'AUTO'}, + '2': {'name': 'ZONE_1'}, + '3': {'name': 'ZONE_2'}, + } + + """ + ProfitBricks is unique in that they allow the user to define all aspects + of the instance size, i.e. disk size, core size, and memory size. + + These are instance types that match up with what other providers support. + + You can configure disk size, core size, and memory size using the ex_ + parameters on the create_node method. + """ + + PROFIT_BRICKS_GENERIC_SIZES = { + '1': { + 'id': '1', + 'name': 'Micro', + 'ram': 1024, + 'disk': 50, + 'cores': 1 + }, + '2': { + 'id': '2', + 'name': 'Small Instance', + 'ram': 2048, + 'disk': 50, + 'cores': 1 + }, + '3': { + 'id': '3', + 'name': 'Medium Instance', + 'ram': 4096, + 'disk': 50, + 'cores': 2 + }, + '4': { + 'id': '4', + 'name': 'Large Instance', + 'ram': 7168, + 'disk': 50, + 'cores': 4 + }, + '5': { + 'id': '5', + 'name': 'ExtraLarge Instance', + 'ram': 14336, + 'disk': 50, + 'cores': 8 + }, + '6': { + 'id': '6', + 'name': 'Memory Intensive Instance Medium', + 'ram': 28672, + 'disk': 50, + 'cores': 4 + }, + '7': { + 'id': '7', + 'name': 'Memory Intensive Instance Large', + 'ram': 57344, + 'disk': 50, + 'cores': 8 + } + } + + """ + Core Functions + """ + + def list_sizes(self): + """ + Lists all sizes + + :rtype: ``list`` of :class:`NodeSize` + """ + sizes = [] + + for key, values in self.PROFIT_BRICKS_GENERIC_SIZES.items(): + node_size = self._to_node_size(values) + sizes.append(node_size) + + return sizes + + def list_images(self): + """ + List all images. + + :rtype: ``list`` of :class:`NodeImage` + """ + + action = 'getAllImages' + body = {'action': action} + + return self._to_images(self.connection.request(action=action, + data=body, method='POST').object) + + def list_locations(self): + """ + List all locations. + """ + locations = [] + + for key, values in self.REGIONS.items(): + location = self._to_location(values) + locations.append(location) + + return locations + + def list_nodes(self): + """ + List all nodes. + + :rtype: ``list`` of :class:`Node` + """ + action = 'getAllServers' + body = {'action': action} + + return self._to_nodes(self.connection.request(action=action, + data=body, method='POST').object) + + def reboot_node(self, node): + """ + Reboots the node. + + :rtype: ``bool`` + """ + action = 'resetServer' + body = {'action': action, + 'serverId': node.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def create_node(self, name, image, size=None, volume=None, + ex_datacenter=None, ex_internet_access=True, + ex_availability_zone=None, ex_ram=None, + ex_cores=None, ex_disk=None, **kwargs): + """ + Creates a node. + + image is optional as long as you pass ram, cores, and disk + to the method. ProfitBricks allows you to adjust compute + resources at a much more granular level. + + :param volume: If the volume already exists then pass this in. + :type volume: :class:`StorageVolume` + + :param ex_datacenter: If you've already created the DC then pass + it in. + :type ex_datacenter: :class:`Datacenter` + + :param ex_internet_access: Configure public Internet access. + :type ex_internet_access: : ``bool`` + + :param ex_availability_zone: The availability zone. + :type ex_availability_zone: class: `ProfitBricksAvailabilityZone` + + :param ex_ram: The amount of ram required. + :type ex_ram: : ``int`` + + :param ex_cores: The number of cores required. + :type ex_cores: : ``int`` + + :param ex_disk: The amount of disk required. + :type ex_disk: : ``int`` + + :return: Instance of class ``Node`` + :rtype: :class:`Node` + """ + if not ex_datacenter: + ''' + We generate a name from the server name passed into the function. + ''' + + 'Creating a Datacenter for the node since one was not provided.' + new_datacenter = self._create_new_datacenter_for_node(name=name) + datacenter_id = new_datacenter.id + + 'Waiting for the Datacenter create operation to finish.' + self._wait_for_datacenter_state(datacenter=new_datacenter) + else: + datacenter_id = ex_datacenter.id + new_datacenter = None + + if not size: + if not ex_ram: + raise ValueError('You need to either pass a ' + 'NodeSize or specify ex_ram as ' + 'an extra parameter.') + if not ex_cores: + raise ValueError('You need to either pass a ' + 'NodeSize or specify ex_cores as ' + 'an extra parameter.') + + if not volume: + if not size: + if not ex_disk: + raise ValueError('You need to either pass a ' + 'StorageVolume, a NodeSize, or specify ' + 'ex_disk as an extra parameter.') + + ''' + You can override the suggested sizes by passing in unique + values for ram, cores, and disk allowing you to size it + for your specific use. + ''' + + if not ex_disk: + ex_disk = size.disk + + if not ex_ram: + ex_ram = size.ram + + if not ex_cores: + ex_cores = size.extra['cores'] + + ''' + A pasword is automatically generated if it is + not provided. This is then sent via email to + the admin contact on record. + ''' + + if 'auth' in kwargs: + auth = self._get_and_check_auth(kwargs["auth"]) + password = auth.password + else: + password = None + + ''' + Create a StorageVolume that can be attached to the + server when it is created. + ''' + if not volume: + volume = self._create_node_volume(ex_disk=ex_disk, + image=image, + password=password, + name=name, + ex_datacenter=ex_datacenter, + new_datacenter=new_datacenter) + + storage_id = volume.id + + 'Waiting on the storage volume to be created before provisioning ' + 'the instance.' + self._wait_for_storage_volume_state(volume) + else: + if ex_datacenter: + datacenter_id = ex_datacenter.id + else: + datacenter_id = volume.extra['datacenter_id'] + + storage_id = volume.id + + action = 'createServer' + body = {'action': action, + 'request': 'true', + 'serverName': name, + 'cores': str(ex_cores), + 'ram': str(ex_ram), + 'bootFromStorageId': storage_id, + 'internetAccess': str(ex_internet_access).lower(), + 'dataCenterId': datacenter_id + } + + if ex_availability_zone: + body['availabilityZone'] = ex_availability_zone.name + + data = self.connection.request(action=action, + data=body, + method='POST').object + nodes = self._to_nodes(data) + return nodes[0] + + def destroy_node(self, node, ex_remove_attached_disks=False): + """ + Destroys a node. + + :param node: The node you wish to destroy. + :type volume: :class:`Node` + + :param ex_remove_attached_disks: True to destory all attached volumes. + :type ex_remove_attached_disks: : ``bool`` + + :rtype: : ``bool`` + """ + action = 'deleteServer' + body = {'action': action, + 'serverId': node.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + """ + Volume Functions + """ + + def list_volumes(self): + """ + Lists all voumes. + """ + action = 'getAllStorages' + body = {'action': action} + + return self._to_volumes(self.connection.request(action=action, + data=body, + method='POST').object) + + def attach_volume(self, node, volume, device=None, ex_bus_type=None): + """ + Attaches a volume. + + :param volume: The volume you're attaching. + :type volume: :class:`StorageVolume` + + :param node: The node to which you're attaching the volume. + :type node: :class:`Node` + + :param device: The device number order. + :type device: : ``int`` + + :param ex_bus_type: Bus type. Either IDE or VIRTIO (default). + :type ex_bus_type: ``str`` + + :return: Instance of class ``StorageVolume`` + :rtype: :class:`StorageVolume` + """ + action = 'connectStorageToServer' + body = {'action': action, + 'request': 'true', + 'storageId': volume.id, + 'serverId': node.id, + 'busType': ex_bus_type, + 'deviceNumber': str(device) + } + + self.connection.request(action=action, + data=body, method='POST').object + return volume + + def create_volume(self, size, name=None, + ex_datacenter=None, ex_image=None, ex_password=None): + """ + Creates a volume. + + :param ex_datacenter: The datacenter you're placing + the storage in. (req) + :type ex_datacenter: :class:`Datacenter` + + :param ex_image: The OS image for the volume. + :type ex_image: :class:`NodeImage` + + :param ex_password: Optional password for root. + :type ex_password: : ``str`` + + :return: Instance of class ``StorageVolume`` + :rtype: :class:`StorageVolume` + """ + action = 'createStorage' + body = {'action': action, + 'request': 'true', + 'size': str(size), + 'storageName': name, + 'mountImageId': ex_image.id + } + + if ex_datacenter: + body['dataCenterId'] = ex_datacenter.id + + if ex_password: + body['profitBricksImagePassword'] = ex_password + + data = self.connection.request(action=action, + data=body, + method='POST').object + volumes = self._to_volumes(data) + return volumes[0] + + def detach_volume(self, volume): + """ + Detaches a volume. + + :param volume: The volume you're detaching. + :type volume: :class:`StorageVolume` + + :rtype: :``bool`` + """ + node_id = volume.extra['server_id'] + + action = 'disconnectStorageFromServer' + body = {'action': action, + 'storageId': volume.id, + 'serverId': node_id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def destroy_volume(self, volume): + """ + Destroys a volume. + + :param volume: The volume you're attaching. + :type volume: :class:`StorageVolume` + + :rtype: : ``bool`` + """ + action = 'deleteStorage' + body = {'action': action, + 'storageId': volume.id} + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_update_volume(self, volume, storage_name=None, size=None): + """ + Updates a volume. + + :param volume: The volume you're attaching.. + :type volume: :class:`StorageVolume` + + :param storage_name: The name of the volume. + :type storage_name: : ``str`` + + :param size: The desired size. + :type size: ``int`` + + :rtype: : ``bool`` + """ + action = 'updateStorage' + body = {'action': action, + 'request': 'true', + 'storageId': volume.id + } + + if storage_name: + body['storageName'] = storage_name + if size: + body['size'] = str(size) + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_describe_volume(self, volume_id): + """ + Describes a volume. + + :param volume_id: The ID of the volume you're describing. + :type volume_id: :class:`StorageVolume` + + :return: Instance of class ``StorageVolume`` + :rtype: :class:`StorageVolume` + """ + action = 'getStorage' + body = {'action': action, + 'storageId': volume_id + } + + data = self.connection.request(action=action, + data=body, + method='POST').object + volumes = self._to_volumes(data) + return volumes[0] + + """ + Extension Functions + """ + + ''' Server Extension Functions + ''' + def ex_stop_node(self, node): + """ + Stops a node. + + This also dealloctes the public IP space. + + :param node: The node you wish to halt. + :type node: :class:`Node` + + :rtype: : ``bool`` + """ + action = 'stopServer' + body = {'action': action, + 'serverId': node.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_start_node(self, node): + """ + Starts a volume. + + :param node: The node you wish to start. + :type node: :class:`Node` + + :rtype: : ``bool`` + """ + action = 'startServer' + body = {'action': action, + 'serverId': node.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_list_availability_zones(self): + """ + Returns a list of availability zones. + """ + + availability_zones = [] + + for key, values in self.AVAILABILITY_ZONE.items(): + name = copy.deepcopy(values)["name"] + + availability_zone = ProfitBricksAvailabilityZone( + name=name + ) + availability_zones.append(availability_zone) + + return availability_zones + + def ex_describe_node(self, node): + """ + Describes a node. + + :param node: The node you wish to describe. + :type node: :class:`Node` + + :return: Instance of class ``Node`` + :rtype: :class:`Node` + """ + action = 'getServer' + body = {'action': action, + 'serverId': node.id + } + + data = self.connection.request(action=action, + data=body, + method='POST').object + nodes = self._to_nodes(data) + return nodes[0] + + def ex_update_node(self, node, name=None, cores=None, + ram=None, availability_zone=None): + """ + Updates a node. + + :param cores: The number of CPUs the node should have. + :type device: : ``int`` + + :param ram: The amount of ram the machine should have. + :type ram: : ``int`` + + :param ex_availability_zone: Update the availability zone. + :type ex_availability_zone: :class:`ProfitBricksAvailabilityZone` + + :rtype: : ``bool`` + """ + action = 'updateServer' + + body = {'action': action, + 'request': 'true', + 'serverId': node.id + } + + if name: + body['serverName'] = name + + if cores: + body['cores'] = str(cores) + + if ram: + body['ram'] = str(ram) + + if availability_zone: + body['availabilityZone'] = availability_zone.name + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + ''' + Datacenter Extension Functions + ''' + + def ex_create_datacenter(self, name, location): + """ + Creates a datacenter. + + ProfitBricks has a concept of datacenters. + These represent buckets into which you + can place various compute resources. + + :param name: The DC name. + :type name: : ``str`` + + :param location: The DC region. + :type location: : ``str`` + + :return: Instance of class ``Datacenter`` + :rtype: :class:`Datacenter` + """ + action = 'createDataCenter' + + body = {'action': action, + 'request': 'true', + 'dataCenterName': name, + 'location': location.lower() + } + data = self.connection.request(action=action, + data=body, + method='POST').object + datacenters = self._to_datacenters(data) + return datacenters[0] + + def ex_destroy_datacenter(self, datacenter): + """ + Destroys a datacenter. + + :param datacenter: The DC you're destroying. + :type datacenter: :class:`Datacenter` + + :rtype: : ``bool`` + """ + action = 'deleteDataCenter' + body = {'action': action, + 'dataCenterId': datacenter.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_describe_datacenter(self, datacenter_id): + """ + Describes a datacenter. + + :param datacenter_id: The DC you are describing. + :type datacenter_id: ``str`` + + :return: Instance of class ``Datacenter`` + :rtype: :class:`Datacenter` + """ + + action = 'getDataCenter' + body = {'action': action, + 'dataCenterId': datacenter_id + } + + data = self.connection.request(action=action, + data=body, + method='POST').object + datacenters = self._to_datacenters(data) + return datacenters[0] + + def ex_list_datacenters(self): + """ + Lists all datacenters. + + :return: ``list`` of class ``Datacenter`` + :rtype: :class:`Datacenter` + """ + action = 'getAllDataCenters' + body = {'action': action} + + return self._to_datacenters(self.connection.request( + action=action, + data=body, + method='POST').object) + + def ex_rename_datacenter(self, datacenter, name): + """ + Update a datacenter. + + :param datacenter: The DC you are renaming. + :type datacenter: :class:`Datacenter` + + :param name: The DC name. + :type name: : ``str`` + + :rtype: : ``bool`` + """ + action = 'updateDataCenter' + body = {'action': action, + 'request': 'true', + 'dataCenterId': datacenter.id, + 'dataCenterName': name + } + + self.connection.request(action=action, + data=body, + method='POST').object + + return True + + def ex_clear_datacenter(self, datacenter): + """ + Clear a datacenter. + + This removes all objects in a DC. + + :param datacenter: The DC you're clearing. + :type datacenter: :class:`Datacenter` + + :rtype: : ``bool`` + """ + action = 'clearDataCenter' + body = {'action': action, + 'dataCenterId': datacenter.id + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + ''' + Network Interface Extension Functions + ''' + + def ex_list_network_interfaces(self): + """ + Lists all network interfaces. + + :return: ``list`` of class ``ProfitBricksNetworkInterface`` + :rtype: :class:`ProfitBricksNetworkInterface` + """ + action = 'getAllNic' + body = {'action': action} + + return self._to_interfaces( + self.connection.request(action=action, + data=body, + method='POST').object) + + def ex_describe_network_interface(self, network_interface): + """ + Describes a network interface. + + :param network_interface: The NIC you wish to describe. + :type network_interface: :class:`ProfitBricksNetworkInterface` + + :return: Instance of class ``ProfitBricksNetworkInterface`` + :rtype: :class:`ProfitBricksNetworkInterface` + """ + action = 'getNic' + body = {'action': action, + 'nicId': network_interface.id + } + + return self._to_interface( + self.connection.request( + action=action, + data=body, + method='POST').object.findall('.//return')[0]) + + def ex_create_network_interface(self, node, + lan_id=None, ip=None, nic_name=None, + dhcp_active=True): + """ + Creates a network interface. + + :param lan_id: The ID for the LAN. + :type lan_id: : ``int`` + + :param ip: The IP address for the NIC. + :type ip: ``str`` + + :param nic_name: The name of the NIC, e.g. PUBLIC. + :type nic_name: ``str`` + + :param dhcp_active: Set to false to disable. + :type dhcp_active: ``bool`` + + :return: Instance of class ``ProfitBricksNetworkInterface`` + :rtype: :class:`ProfitBricksNetworkInterface` + """ + action = 'createNic' + body = {'action': action, + 'request': 'true', + 'serverId': node.id, + 'dhcpActive': str(dhcp_active) + } + + if lan_id: + body['lanId'] = str(lan_id) + else: + body['lanId'] = str(1) + + if ip: + body['ip'] = ip + + if nic_name: + body['nicName'] = nic_name + + data = self.connection.request(action=action, + data=body, + method='POST').object + interfaces = self._to_interfaces(data) + return interfaces[0] + + def ex_update_network_interface(self, network_interface, name=None, + lan_id=None, ip=None, + dhcp_active=None): + """ + Updates a network interface. + + :param lan_id: The ID for the LAN. + :type lan_id: : ``int`` + + :param ip: The IP address for the NIC. + :type ip: ``str`` + + :param name: The name of the NIC, e.g. PUBLIC. + :type name: ``str`` + + :param dhcp_active: Set to false to disable. + :type dhcp_active: ``bool`` + + :rtype: : ``bool`` + """ + action = 'updateNic' + body = {'action': action, + 'request': 'true', + 'nicId': network_interface.id + } + + if name: + body['nicName'] = name + + if lan_id: + body['lanId'] = str(lan_id) + + if ip: + body['ip'] = ip + + if dhcp_active is not None: + body['dhcpActive'] = str(dhcp_active).lower() + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_destroy_network_interface(self, network_interface): + """ + Destroy a network interface. + + :param network_interface: The NIC you wish to describe. + :type network_interface: :class:`ProfitBricksNetworkInterface` + + :rtype: : ``bool`` + """ + + action = 'deleteNic' + body = {'action': action, + 'nicId': network_interface.id} + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + def ex_set_inet_access(self, datacenter, + network_interface, internet_access=True): + + action = 'setInternetAccess' + + body = {'action': action, + 'dataCenterId': datacenter.id, + 'lanId': network_interface.extra['lan_id'], + 'internetAccess': str(internet_access).lower() + } + + self.connection.request(action=action, + data=body, method='POST').object + + return True + + """ + Private Functions + """ + + def _to_datacenters(self, object): + return [self._to_datacenter( + datacenter) for datacenter in object.findall('.//return')] + + def _to_datacenter(self, datacenter): + datacenter_id = datacenter.find('dataCenterId').text + if ET.iselement(datacenter.find('dataCenterName')): + datacenter_name = datacenter.find('dataCenterName').text + else: + datacenter_name = None + version = datacenter.find('dataCenterVersion').text + if ET.iselement(datacenter.find('provisioningState')): + provisioning_state = datacenter.find('provisioningState').text + else: + provisioning_state = None + if ET.iselement(datacenter.find('location')): + location = datacenter.find('location').text + else: + location = None + + provisioning_state = self.PROVISIONING_STATE.get(provisioning_state, + NodeState.UNKNOWN) + + return Datacenter(id=datacenter_id, + name=datacenter_name, + version=version, + driver=self.connection.driver, + extra={'provisioning_state': provisioning_state, + 'location': location}) + + def _to_images(self, object): + return [self._to_image(image) for image in object.findall('.//return')] + + def _to_image(self, image): + image_id = image.find('imageId').text + image_name = image.find('imageName').text + image_size = image.find('imageSize').text + image_type = image.find('imageType').text + os_type = image.find('osType').text + public = image.find('public').text + writeable = image.find('writeable').text + + if ET.iselement(image.find('cpuHotpluggable')): + cpu_hotpluggable = image.find('cpuHotpluggable').text + else: + cpu_hotpluggable = None + + if ET.iselement(image.find('memoryHotpluggable')): + memory_hotpluggable = image.find('memoryHotpluggable').text + else: + memory_hotpluggable = None + + if ET.iselement(image.find('location')): + if image.find('region'): + image_region = image.find('region').text + else: + image_region = None + else: + image_region = None + + return NodeImage(id=image_id, + name=image_name, + driver=self.connection.driver, + extra={'image_size': image_size, + 'image_type': image_type, + 'cpu_hotpluggable': cpu_hotpluggable, + 'memory_hotpluggable': memory_hotpluggable, + 'os_type': os_type, + 'public': public, + 'location': image_region, + 'writeable': writeable}) + + def _to_nodes(self, object): + return [self._to_node(n) for n in object.findall('.//return')] + + def _to_node(self, node): + """ + Convert the request into a node Node + """ + ATTRIBUTE_NAME_MAP = { + 'dataCenterId': 'datacenter_id', + 'dataCenterVersion': 'datacenter_version', + 'serverId': 'node_id', + 'serverName': 'node_name', + 'cores': 'cores', + 'ram': 'ram', + 'internetAccess': 'internet_access', + 'provisioningState': 'provisioning_state', + 'virtualMachineState': 'virtual_machine_state', + 'creationTime': 'creation_time', + 'lastModificationTime': 'last_modification_time', + 'osType': 'os_type', + 'availabilityZone': 'availability_zone', + 'cpuHotPlug': 'cpu_hotpluggable', + 'ramHotPlug': 'memory_hotpluggable', + 'nicHotPlug': 'nic_hotpluggable', + 'discVirtioHotPlug': 'disc_virtio_hotplug', + 'discVirtioHotUnPlug': 'disc_virtio_hotunplug' + } + + extra = {} + for attribute_name, extra_name in ATTRIBUTE_NAME_MAP.items(): + elem = node.find(attribute_name) + + if ET.iselement(elem): + value = elem.text + else: + value = None + + extra[extra_name] = value + + public_ips = [] + private_ips = [] + + if ET.iselement(node.find('nics')): + for nic in node.findall('.//nics'): + n_elements = list(nic.findall('.//ips')) + if len(n_elements) > 0: + ip = n_elements[0].text + if is_private_subnet(ip): + private_ips.append(ip) + else: + public_ips.append(ip) + + extra['provisioning_state'] = self.PROVISIONING_STATE.get( + extra['provisioning_state'], NodeState.UNKNOWN) + + node_id = extra['node_id'] + node_name = extra['node_name'] + state = self.NODE_STATE_MAP.get(extra['virtual_machine_state'], + NodeState.UNKNOWN) + + return Node( + id=node_id, + name=node_name, + state=state, + public_ips=public_ips, + private_ips=private_ips, + driver=self.connection.driver, + extra=extra) + + def _to_volumes(self, object): + return [self._to_volume( + volume) for volume in object.findall('.//return')] + + def _to_volume(self, volume, node=None): + ATTRIBUTE_NAME_MAP = { + 'dataCenterId': 'datacenter_id', + 'storageId': 'storage_id', + 'storageName': 'storage_name', + 'serverIds': 'server_id', + 'creationTime': 'creation_time', + 'lastModificationTime': 'last_modification_time', + 'provisioningState': 'provisioning_state', + 'size': 'size', + } + + extra = {} + for attribute_name, extra_name in ATTRIBUTE_NAME_MAP.items(): + elem = volume.find(attribute_name) + + if ET.iselement(elem): + value = elem.text + else: + value = None + + extra[extra_name] = value + + if ET.iselement(volume.find('mountImage')): + image_id = volume.find('mountImage')[0].text + image_name = volume.find('mountImage')[1].text + else: + image_id = None + image_name = None + + extra['image_id'] = image_id + extra['image_name'] = image_name + extra['size'] = int(extra['size']) if extra['size'] else 0 + extra['provisioning_state'] = \ + self.PROVISIONING_STATE.get(extra['provisioning_state'], + NodeState.UNKNOWN) + + storage_id = extra['storage_id'] + storage_name = extra['storage_name'] + size = extra['size'] + + return StorageVolume( + id=storage_id, + name=storage_name, + size=size, + driver=self.connection.driver, + extra=extra) + + def _to_interfaces(self, object): + return [self._to_interface( + interface) for interface in object.findall('.//return')] + + def _to_interface(self, interface): + ATTRIBUTE_NAME_MAP = { + 'nicId': 'nic_id', + 'nicName': 'nic_name', + 'serverId': 'server_id', + 'lanId': 'lan_id', + 'internetAccess': 'internet_access', + 'macAddress': 'mac_address', + 'dhcpActive': 'dhcp_active', + 'gatewayIp': 'gateway_ip', + 'provisioningState': 'provisioning_state', + 'dataCenterId': 'datacenter_id', + 'dataCenterVersion': 'datacenter_version' + } + + extra = {} + for attribute_name, extra_name in ATTRIBUTE_NAME_MAP.items(): + elem = interface.find(attribute_name) + + if ET.iselement(elem): + value = elem.text + else: + value = None + + extra[extra_name] = value + + ips = [] + + if ET.iselement(interface.find('ips')): + for ip in interface.findall('.//ips'): + ips.append(ip.text) + + extra['ips'] = ips + + nic_id = extra['nic_id'] + nic_name = extra['nic_name'] + state = self.PROVISIONING_STATE.get(extra['provisioning_state'], + NodeState.UNKNOWN) + + return ProfitBricksNetworkInterface( + id=nic_id, + name=nic_name, + state=state, + extra=extra) + + def _to_location(self, data): + + return NodeLocation(id=data["region"], + name=data["region"], + country=data["country"], + driver=self.connection.driver) + + def _to_node_size(self, data): + """ + Convert the PROFIT_BRICKS_GENERIC_SIZES into NodeSize + """ + return NodeSize(id=data["id"], + name=data["name"], + ram=data["ram"], + disk=data["disk"], + bandwidth=None, + price=None, + driver=self.connection.driver, + extra={ + 'cores': data["cores"]}) + + def _wait_for_datacenter_state(self, datacenter, state=NodeState.RUNNING, + timeout=300, interval=5): + """ + Private function that waits the datacenter to transition into the + specified state. + + :return: Datacenter object on success. + :rtype: :class:`.Datacenter` + """ + wait_time = 0 + datacenter = self.ex_describe_datacenter(datacenter_id=datacenter.id) + + while (datacenter.extra['provisioning_state'] != state): + datacenter = \ + self.ex_describe_datacenter(datacenter_id=datacenter.id) + if datacenter.extra['provisioning_state'] == state: + break + + if wait_time >= timeout: + raise Exception('Datacenter didn\'t transition to %s state ' + 'in %s seconds' % (state, timeout)) + + wait_time += interval + time.sleep(interval) + + return datacenter + + def _create_new_datacenter_for_node(self, name): + """ + Creates a Datacenter for a node. + """ + dc_name = name + '-DC' + + return self.ex_create_datacenter(name=dc_name, location='us/las') + + def _wait_for_storage_volume_state(self, volume, state=NodeState.RUNNING, + timeout=300, interval=5): + """ + Wait for volume to transition into the specified state. + + :return: Volume object on success. + :rtype: :class:`Volume` + """ + wait_time = 0 + volume = self.ex_describe_volume(volume_id=volume.id) + + while (volume.extra['provisioning_state'] != state): + volume = self.ex_describe_volume(volume_id=volume.id) + if volume.extra['provisioning_state'] == state: + break + + if wait_time >= timeout: + raise Exception('Volume didn\'t transition to %s state ' + 'in %s seconds' % (state, timeout)) + + wait_time += interval + time.sleep(interval) + + return volume + + def _create_node_volume(self, ex_disk, image, password, + name, ex_datacenter=None, new_datacenter=None): + + volume_name = name + '-volume' + + if ex_datacenter: + volume = self.create_volume(size=ex_disk, + ex_datacenter=ex_datacenter, + ex_image=image, + ex_password=password, + name=volume_name) + else: + volume = self.create_volume(size=ex_disk, + ex_datacenter=new_datacenter, + ex_image=image, + ex_password=password, + name=volume_name) + + return volume http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/compute/providers.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py index 5c19f61..b449e78 100644 --- a/libcloud/compute/providers.py +++ b/libcloud/compute/providers.py @@ -149,6 +149,8 @@ DRIVERS = { ('libcloud.compute.drivers.ec2', 'OutscaleINCNodeDriver'), Provider.VSPHERE: ('libcloud.compute.drivers.vsphere', 'VSphereNodeDriver'), + Provider.PROFIT_BRICKS: + ('libcloud.compute.drivers.profitbricks', 'ProfitBricksNodeDriver'), # Deprecated Provider.CLOUDSIGMA_US: http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/compute/types.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py index c7c7616..f07bc48 100644 --- a/libcloud/compute/types.py +++ b/libcloud/compute/types.py @@ -76,6 +76,7 @@ class Provider(object): :cvar IKOULA: Ikoula driver. :cvar OUTSCALE_SAS: Outscale SAS driver. :cvar OUTSCALE_INC: Outscale INC driver. + :cvar PROFIT_BRICKS: ProfitBricks driver. """ DUMMY = 'dummy' EC2 = 'ec2_us_east' @@ -122,6 +123,7 @@ class Provider(object): OUTSCALE_SAS = 'outscale_sas' OUTSCALE_INC = 'outscale_inc' VSPHERE = 'vsphere' + PROFIT_BRICKS = 'profitbricks' # OpenStack based providers HPCLOUD = 'hpcloud' http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/attach_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/attach_volume.xml b/libcloud/test/compute/fixtures/profitbricks/attach_volume.xml new file mode 100644 index 0000000..8b2b1f5 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/attach_volume.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:connectStorageToServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3613039</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>4</dataCenterVersion> + </return> + </ns2:connectStorageToServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/create_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/create_node.xml b/libcloud/test/compute/fixtures/profitbricks/create_node.xml new file mode 100644 index 0000000..ad515ba --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/create_node.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:createServerReturn xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3768523</requestId> + <dataCenterId>3aefc31b-57e9-4af6-8348-af961ac00f74</dataCenterId> + <dataCenterVersion>3</dataCenterVersion> + <serverId>7b18b85f-cc93-4c2d-abcc-5ce732d35750</serverId> + </return> + </ns2:createServerReturn> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/create_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/create_volume.xml b/libcloud/test/compute/fixtures/profitbricks/create_volume.xml new file mode 100644 index 0000000..326879a --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/create_volume.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:createStorageReturn xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3532463</requestId> + <dataCenterId>06eac419-c2b3-4761-aeb9-10efdd2cf292</dataCenterId> + <dataCenterVersion>3</dataCenterVersion> + <storageId>f54aeea3-667a-4460-8cf0-80909509df0c</storageId> + </return> + </ns2:createStorageReturn> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/destroy_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/destroy_node.xml b/libcloud/test/compute/fixtures/profitbricks/destroy_node.xml new file mode 100644 index 0000000..1dacfaf --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/destroy_node.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:deleteServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3498434</requestId> + <dataCenterId>782247bf-f12d-4f08-8050-302c02c4b2e0</dataCenterId> + <dataCenterVersion>2</dataCenterVersion> + </return> + </ns2:deleteServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/destroy_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/destroy_volume.xml b/libcloud/test/compute/fixtures/profitbricks/destroy_volume.xml new file mode 100644 index 0000000..0591e1c --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/destroy_volume.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:deleteStorageResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3616447</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>13</dataCenterVersion> + </return> + </ns2:deleteStorageResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/detach_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/detach_volume.xml b/libcloud/test/compute/fixtures/profitbricks/detach_volume.xml new file mode 100644 index 0000000..fafc327 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/detach_volume.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:disconnectStorageFromServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3614242</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>6</dataCenterVersion> + </return> + </ns2:disconnectStorageFromServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_clear_datacenter.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_clear_datacenter.xml b/libcloud/test/compute/fixtures/profitbricks/ex_clear_datacenter.xml new file mode 100644 index 0000000..5259d45 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_clear_datacenter.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:clearDataCenterResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3339052</requestId> + <dataCenterId>8669a69f-2274-4520-b51e-dbdf3986a476</dataCenterId> + <dataCenterVersion>2</dataCenterVersion> + </return> + </ns2:clearDataCenterResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.xml b/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.xml new file mode 100644 index 0000000..f4238d8 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:createDataCenterResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3711001</requestId> + <dataCenterId>0c793dd1-d4cd-4141-86f3-8b1a24b2d604</dataCenterId> + <dataCenterVersion>1</dataCenterVersion> + <location>us/las</location> + </return> + </ns2:createDataCenterResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.xml b/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.xml new file mode 100644 index 0000000..830d41d --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:createNicReturn xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3633314</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>27</dataCenterVersion> + <nicId>951e1b49-5f1b-4b2b-b7d9-263dba6e2ddd</nicId> + </return> + </ns2:createNicReturn> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.xml b/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.xml new file mode 100644 index 0000000..cb4a1a0 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getDataCenterResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3719240</requestId> + <dataCenterId>a3e6f83a-8982-4d6a-aebc-60baf5755ede</dataCenterId> + <dataCenterVersion>1</dataCenterVersion> + <dataCenterName>StackPointCloud</dataCenterName> + <provisioningState>AVAILABLE</provisioningState> + <location>us/las</location> + </return> + </ns2:getDataCenterResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.xml b/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.xml new file mode 100644 index 0000000..e2235b9 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getNicResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3707226</requestId> + <dataCenterId>a3a2e730-0dc3-47e6-bac6-4c056d5e2aee</dataCenterId> + <dataCenterVersion>6</dataCenterVersion> + <nicId>f1c7a244-2fa6-44ee-8fb6-871f337683a3</nicId> + <lanId>1</lanId> + <internetAccess>false</internetAccess> + <serverId>c09f4f31-336c-4ad2-9ec7-591778513408</serverId> + <ips>10.10.38.12</ips> + <macAddress>02:01:96:d7:60:e0</macAddress> + <firewall> + <active>false</active> + <firewallId>01490a19-2b20-43cc-86a4-ff0b0460f076</firewallId> + <nicId>f1c7a244-2fa6-44ee-8fb6-871f337683a3</nicId> + <provisioningState>AVAILABLE</provisioningState> + </firewall> + <dhcpActive>true</dhcpActive> + <provisioningState>AVAILABLE</provisioningState> + </return> + </ns2:getNicResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.xml b/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.xml new file mode 100644 index 0000000..5567e8f --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3706813</requestId> + <dataCenterId>a3a2e730-0dc3-47e6-bac6-4c056d5e2aee</dataCenterId> + <dataCenterVersion>6</dataCenterVersion> + <serverId>c09f4f31-336c-4ad2-9ec7-591778513408</serverId> + <serverName>server001</serverName> + <cores>1</cores> + <ram>1024</ram> + <internetAccess>true</internetAccess> + <ips>10.10.38.12</ips> + <ips>162.254.26.14</ips> + <connectedStorages> + <bootDevice>true</bootDevice> + <busType>VIRTIO</busType> + <deviceNumber>1</deviceNumber> + <size>50</size> + <storageId>addb19d8-e664-43c1-bd2d-ad9210edc610</storageId> + <storageName>storage001</storageName> + </connectedStorages> + <nics> + <dataCenterId>a3a2e730-0dc3-47e6-bac6-4c056d5e2aee</dataCenterId> + <dataCenterVersion>6</dataCenterVersion> + <nicId>f1c7a244-2fa6-44ee-8fb6-871f337683a3</nicId> + <lanId>1</lanId> + <internetAccess>false</internetAccess> + <serverId>c09f4f31-336c-4ad2-9ec7-591778513408</serverId> + <ips>10.10.38.12</ips> + <macAddress>02:01:96:d7:60:e0</macAddress> + <firewall> + <active>false</active> + <firewallId>01490a19-2b20-43cc-86a4-ff0b0460f076</firewallId> + <nicId>f1c7a244-2fa6-44ee-8fb6-871f337683a3</nicId> + <provisioningState>AVAILABLE</provisioningState> + </firewall> + <dhcpActive>true</dhcpActive> + <provisioningState>AVAILABLE</provisioningState> + </nics> + <nics> + <dataCenterId>a3a2e730-0dc3-47e6-bac6-4c056d5e2aee</dataCenterId> + <dataCenterVersion>6</dataCenterVersion> + <nicId>e6263870-cd70-42e4-956a-00f3bbec70e3</nicId> + <nicName>PUBLIC</nicName> + <lanId>3</lanId> + <internetAccess>true</internetAccess> + <serverId>c09f4f31-336c-4ad2-9ec7-591778513408</serverId> + <ips>162.254.26.14</ips> + <macAddress>02:01:9c:53:c3:50</macAddress> + <firewall> + <active>false</active> + <firewallId>c0fa291e-38c2-48a6-bd15-b66ba54ac18a</firewallId> + <nicId>e6263870-cd70-42e4-956a-00f3bbec70e3</nicId> + <provisioningState>AVAILABLE</provisioningState> + </firewall> + <dhcpActive>false</dhcpActive> + <gatewayIp>162.254.26.1</gatewayIp> + <provisioningState>AVAILABLE</provisioningState> + </nics> + <provisioningState>AVAILABLE</provisioningState> + <virtualMachineState>RUNNING</virtualMachineState> + <creationTime>2014-07-16T18:53:05.109Z</creationTime> + <lastModificationTime>2014-07-16T19:57:51.577Z</lastModificationTime> + <osType>LINUX</osType> + <availabilityZone>AUTO</availabilityZone> + <cpuHotPlug>true</cpuHotPlug> + <ramHotPlug>true</ramHotPlug> + <nicHotPlug>true</nicHotPlug> + <nicHotUnPlug>true</nicHotUnPlug> + <discVirtioHotPlug>true</discVirtioHotPlug> + <discVirtioHotUnPlug>true</discVirtioHotUnPlug> + </return> + </ns2:getServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.xml b/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.xml new file mode 100644 index 0000000..050b4b5 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getStorageResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3767716</requestId> + <dataCenterId>905f1346-d199-425d-a035-7dc28f6819cd</dataCenterId> + <dataCenterVersion>2</dataCenterVersion> + <storageId>00d0b9e7-e016-456f-85a0-517aa9a34bf5</storageId> + <size>50</size> + <storageName>StackPointCloud-Volume</storageName> + <mountImage> + <imageId>cd59b162-0289-11e4-9f63-52540066fee9</imageId> + <imageName>Debian-7-server-2014-07-01</imageName> + </mountImage> + <provisioningState>AVAILABLE</provisioningState> + <creationTime>2014-07-21T17:37:45.958Z</creationTime> + <lastModificationTime>2014-07-21T17:37:45.958Z</lastModificationTime> + </return> + </ns2:getStorageResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_destroy_datacenter.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_destroy_datacenter.xml b/libcloud/test/compute/fixtures/profitbricks/ex_destroy_datacenter.xml new file mode 100644 index 0000000..4d36bdb --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_destroy_datacenter.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:deleteDataCenterResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3339313</requestId> + </return> + </ns2:deleteDataCenterResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_destroy_network_interface.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_destroy_network_interface.xml b/libcloud/test/compute/fixtures/profitbricks/ex_destroy_network_interface.xml new file mode 100644 index 0000000..6584f06 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_destroy_network_interface.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:deleteNicResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3634902</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>31</dataCenterVersion> + </return> + </ns2:deleteNicResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.xml b/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.xml new file mode 100644 index 0000000..dfb9245 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getAllDataCentersResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <dataCenterId>a3e6f83a-8982-4d6a-aebc-60baf5755ede</dataCenterId> + <dataCenterName>StackPointCloud</dataCenterName> + <dataCenterVersion>1</dataCenterVersion> + <provisioningState>AVAILABLE</provisioningState> + </return> + <return> + <dataCenterId>c68f77b8-7ecb-40e9-8b41-79415dffc0f1</dataCenterId> + <dataCenterName>XYZ</dataCenterName> + <dataCenterVersion>2</dataCenterVersion> + <provisioningState>AVAILABLE</provisioningState> + </return> + </ns2:getAllDataCentersResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.xml b/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.xml new file mode 100644 index 0000000..7164f22 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getAllNicResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>26</dataCenterVersion> + <nicId>6b38a4f3-b851-4614-9e3a-5ddff4727727</nicId> + <nicName>StackPointCloud</nicName> + <lanId>3</lanId> + <internetAccess>false</internetAccess> + <serverId>234f0cf9-1efc-4ade-b829-036456584116</serverId> + <ips>10.14.96.11</ips> + <ips>162.254.26.14</ips> + <ips>162.254.26.15</ips> + <macAddress>02:01:40:47:90:04</macAddress> + <firewall> + <active>false</active> + <firewallId>e93f74b2-d969-4b7d-8fad-3931b85dbc4d</firewallId> + <firewallRules> + <firewallRuleId>d6f7e726-c13d-464c-b454-cae726dac75d</firewallRuleId> + <protocol>ANY</protocol> + <sourceIp>1.2.3.4</sourceIp> + <targetIp>1.2.3.4</targetIp> + </firewallRules> + <firewallRules> + <firewallRuleId>87773a01-b7e2-481e-8a44-d5ffac830292</firewallRuleId> + <protocol>ICMP</protocol> + </firewallRules> + <nicId>6b38a4f3-b851-4614-9e3a-5ddff4727727</nicId> + <provisioningState>AVAILABLE</provisioningState> + </firewall> + <dhcpActive>true</dhcpActive> + <provisioningState>AVAILABLE</provisioningState> + </return> + <return> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>26</dataCenterVersion> + <nicId>47e3b2ce-7846-41cc-8404-1475190e89a3</nicId> + <lanId>3</lanId> + <internetAccess>false</internetAccess> + <serverId>7fb5d34c-77c2-4452-b7b2-274fa0f46327</serverId> + <ips>10.14.96.12</ips> + <macAddress>02:01:fe:1c:81:73</macAddress> + <firewall> + <active>false</active> + <firewallId>d3d1d8b9-0dd5-4866-8429-a1817be7b6e9</firewallId> + <nicId>47e3b2ce-7846-41cc-8404-1475190e89a3</nicId> + <provisioningState>AVAILABLE</provisioningState> + </firewall> + <dhcpActive>true</dhcpActive> + <provisioningState>AVAILABLE</provisioningState> + </return> + <return> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>26</dataCenterVersion> + <nicId>cbd00ace-d210-43e8-8cb7-097ad6b33e82</nicId> + <lanId>1</lanId> + <internetAccess>true</internetAccess> + <serverId>234f0cf9-1efc-4ade-b829-036456584116</serverId> + <ips>208.94.38.110</ips> + <macAddress>02:01:e9:20:cd:81</macAddress> + <firewall> + <active>false</active> + <firewallId>a1a2e1da-7672-4a5c-af62-6c37edaffd26</firewallId> + <nicId>cbd00ace-d210-43e8-8cb7-097ad6b33e82</nicId> + <provisioningState>INPROCESS</provisioningState> + </firewall> + <dhcpActive>true</dhcpActive> + <gatewayIp>208.94.38.1</gatewayIp> + <provisioningState>AVAILABLE</provisioningState> + </return> + </ns2:getAllNicResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_start_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_start_node.xml b/libcloud/test/compute/fixtures/profitbricks/ex_start_node.xml new file mode 100644 index 0000000..f83d6a4 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_start_node.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:stopServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3494585</requestId> + </return> + </ns2:stopServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_stop_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_stop_node.xml b/libcloud/test/compute/fixtures/profitbricks/ex_stop_node.xml new file mode 100644 index 0000000..f83d6a4 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_stop_node.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:stopServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3494585</requestId> + </return> + </ns2:stopServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_update_datacenter.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_datacenter.xml b/libcloud/test/compute/fixtures/profitbricks/ex_update_datacenter.xml new file mode 100644 index 0000000..270aa41 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_datacenter.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:updateDataCenterResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3325148</requestId> + <dataCenterId>d96dfafc-9a8c-4c0e-8a0c-857a15db572d</dataCenterId> + <dataCenterVersion>3</dataCenterVersion> + </return> + </ns2:updateDataCenterResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.xml b/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.xml new file mode 100644 index 0000000..f9f8e0d --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:updateNicResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3665310</requestId> + <dataCenterId>aab9454d-c442-4d06-9dd7-7c6121ae5ca2</dataCenterId> + <dataCenterVersion>3</dataCenterVersion> + </return> + </ns2:updateNicResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_update_node.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_node.xml b/libcloud/test/compute/fixtures/profitbricks/ex_update_node.xml new file mode 100644 index 0000000..03693a7 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_node.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:updateServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3623299</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>18</dataCenterVersion> + </return> + </ns2:updateServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.xml b/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.xml new file mode 100644 index 0000000..03693a7 --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:updateServerResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <requestId>3623299</requestId> + <dataCenterId>c2df1871-6aac-458e-ad1a-ef3f530cb7aa</dataCenterId> + <dataCenterVersion>18</dataCenterVersion> + </return> + </ns2:updateServerResponse> + </S:Body> +</S:Envelope> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/34cff301/libcloud/test/compute/fixtures/profitbricks/list_images.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/profitbricks/list_images.xml b/libcloud/test/compute/fixtures/profitbricks/list_images.xml new file mode 100644 index 0000000..3c8ac7b --- /dev/null +++ b/libcloud/test/compute/fixtures/profitbricks/list_images.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> + <S:Body> + <ns2:getAllImagesResponse xmlns:ns2="http://ws.api.profitbricks.com/"> + <return> + <cpuHotpluggable>false</cpuHotpluggable> + <imageId>03b6c3e7-f2ad-11e3-a036-52540066fee9</imageId> + <imageName>windows-2012-r2-server-2014-06</imageName> + <imageSize>11264</imageSize> + <imageType>HDD</imageType> + <memoryHotpluggable>false</memoryHotpluggable> + <osType>WINDOWS</osType> + <public>true</public> + <region>NORTH_AMERICA</region> + <writeable>true</writeable> + </return> + <return> + <cpuHotpluggable>true</cpuHotpluggable> + <imageId>cd59b162-0289-11e4-9f63-52540066fee9</imageId> + <imageName>Debian-7-server-2014-07-01</imageName> + <imageSize>2048</imageSize> + <imageType>HDD</imageType> + <memoryHotpluggable>true</memoryHotpluggable> + <osType>LINUX</osType> + <public>true</public> + <region>NORTH_AMERICA</region> + <writeable>true</writeable> + </return> + <return> + <cpuHotpluggable>true</cpuHotpluggable> + <imageId>d2f627c4-0289-11e4-9f63-52540066fee9</imageId> + <imageName>CentOS-6-server-2014-07-01</imageName> + <imageSize>2048</imageSize> + <imageType>HDD</imageType> + <memoryHotpluggable>true</memoryHotpluggable> + <osType>LINUX</osType> + <public>true</public> + <region>NORTH_AMERICA</region> + <writeable>true</writeable> + </return> + </ns2:getAllImagesResponse> + </S:Body> +</S:Envelope> \ No newline at end of file
