You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2016/11/14 04:18:01 UTC

[1/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Repository: libcloud
Updated Branches:
  refs/heads/trunk 54050a418 -> df93d65f6


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/test_profitbricks.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_profitbricks.py b/libcloud/test/compute/test_profitbricks.py
index 0a5c068..c246136 100644
--- a/libcloud/test/compute/test_profitbricks.py
+++ b/libcloud/test/compute/test_profitbricks.py
@@ -32,478 +32,5157 @@ class ProfitBricksTests(unittest.TestCase):
         ProfitBricks.connectionCls.conn_classes = (None, ProfitBricksMockHttp)
         self.driver = ProfitBricks(*PROFIT_BRICKS_PARAMS)
 
-    ''' Server Function Tests
     '''
-    def test_list_nodes(self):
-        nodes = self.driver.list_nodes()
-
-        self.assertEqual(len(nodes), 3)
+    Function tests for listing items
+    '''
 
-        node = nodes[0]
-        self.assertEqual(node.id, "c8e57d7b-e731-46ad-a913-1828c0562246")
-        self.assertEqual(node.name, "server001")
-        self.assertEqual(node.state, NodeState.RUNNING)
-        self.assertEqual(node.public_ips, ['162.254.25.197'])
-        self.assertEqual(node.private_ips, ['10.10.108.12', '10.13.198.11'])
-        self.assertEqual(node.extra['datacenter_id'], "e1e8ec0d-b47f-4d39-a91b-6e885483c899")
-        self.assertEqual(node.extra['datacenter_version'], "5")
-        self.assertEqual(node.extra['provisioning_state'], NodeState.RUNNING)
-        self.assertEqual(node.extra['creation_time'], "2014-07-14T20:52:20.839Z")
-        self.assertEqual(node.extra['last_modification_time'], "2014-07-14T22:11:09.324Z")
-        self.assertEqual(node.extra['os_type'], "LINUX")
-        self.assertEqual(node.extra['availability_zone'], "ZONE_1")
+    def test_list_sizes(self):
+        sizes = self.driver.list_sizes()
+        self.assertEqual(len(sizes), 7)
 
-    def test_ex_describe_node(self):
-        image = type('NodeImage', (object,),
-                     dict(id="cd59b162-0289-11e4-9f63-52540066fee9",
-                          name="Debian-7-server-2014-07-01"))
-        size = type('NodeSize', (object,),
-                    dict(id="2",
-                         name="Small Instance",
-                         ram=2048,
-                         disk=50,
-                         extra={'cores': 1}))
-
-        node = self.driver.create_node(name="SPC-Server",
-                                       image=image,
-                                       size=size)
-
-        self.assertEqual(node.id, "7b18b85f-cc93-4c2d-abcc-5ce732d35750")
+    def test_list_images(self):
 
-    def test_reboot_node(self):
-        node = type('Node', (object,),
-                    dict(id="c8e57d7b-e731-46ad-a913-1828c0562246"))
-        reboot = self.driver.reboot_node(node=node)
+        '''
+        Fetch all images and then fetch with filters
+        '''
+        all_images = self.driver.list_images()
+        hdd_images = self.driver.list_images('HDD')
+        cdd_images = self.driver.list_images('CDROM')
+        private_images = self.driver.list_images(is_public=False)
+
+        self.assertEqual(len(all_images), 4)
+        self.assertEqual(len(hdd_images), 2)
+        self.assertEqual(len(cdd_images), 2)
+        self.assertEqual(len(private_images), 2)
+
+        image = all_images[0]
+        extra = image.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(image.id, 'img-1')
+        self.assertEqual(image.name, 'Test-Image-Two-CDROM')
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(extra['created_date'], '2014-11-14T15:22:19Z')
+        self.assertEqual(extra['created_by'], 'System')
+        self.assertEqual(extra['etag'], '957e0eac7456fa7554e73bf0d18860eb')
+        self.assertEqual(extra['last_modified_date'], '2014-11-14T15:22:19Z')
+        self.assertEqual(extra['last_modified_by'], 'System')
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(extra['name'], 'Test-Image-Two-CDROM')
+        self.assertEqual(extra['description'], '')
+        self.assertEqual(extra['location'], 'us/las')
+        self.assertEqual(extra['size'], 4)
+        self.assertEqual(extra['cpu_hot_plug'], False)
+
+        self.assertEqual(extra['cpu_hot_unplug'], False)
+        self.assertEqual(extra['ram_hot_plug'], False)
+        self.assertEqual(extra['ram_hot_unplug'], False)
+        self.assertEqual(extra['nic_hot_plug'], False)
+        self.assertEqual(extra['nic_hot_unplug'], False)
+
+        self.assertEqual(extra['disc_virtio_hot_plug'], False)
+        self.assertEqual(extra['disc_virtio_hot_unplug'], False)
+        self.assertEqual(extra['disc_scsi_hot_plug'], False)
+        self.assertEqual(extra['disc_scsi_hot_unplug'], False)
+        self.assertEqual(extra['licence_type'], 'OTHER')
+
+        self.assertEqual(extra['image_type'], 'CDROM')
+        self.assertEqual(extra['public'], True)
 
-        self.assertTrue(reboot)
+    def test_list_locations(self):
 
-    def test_ex_stop_node(self):
-        node = type('Node', (object,),
-                    dict(id="c8e57d7b-e731-46ad-a913-1828c0562246"))
-        stop = self.driver.ex_stop_node(node=node)
+        locations = self.driver.list_locations()
 
-        self.assertTrue(stop)
+        self.assertEqual(len(locations), 3)
 
-    def test_ex_start_node(self):
-        node = type('Node', (object,),
-                    dict(id="c8e57d7b-e731-46ad-a913-1828c0562246"))
-        start = self.driver.ex_start_node(node=node)
+        '''
+        Standard properties
+        '''
+        location = locations[0]
+        self.assertEqual(location.id, 'de/fkb')
+        self.assertEqual(location.name, 'karlsruhe')
+        self.assertEqual(location.country, 'de')
 
-        self.assertTrue(start)
+    def test_list_nodes(self):
 
-    def test_destroy_node(self):
-        node = type('Node', (object,),
-                    dict(id="c8e57d7b-e731-46ad-a913-1828c0562246"))
-        destroy = self.driver.destroy_node(node=node)
+        nodes = self.driver.list_nodes()
 
-        self.assertTrue(destroy)
+        self.assertEqual(len(nodes), 2)
 
-    def test_ex_update_node(self):
-        node = type('Node', (object,),
-                    dict(id="c8e57d7b-e731-46ad-a913-1828c0562246"))
+        node = nodes[0]
+        extra = node.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            node.id,
+            'srv-1'
+        )
+        self.assertEqual(
+            node.name,
+            'Test Node.'
+        )
+        self.assertEqual(
+            node.state,
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            node.public_ips,
+            []
+        )
+        self.assertEqual(
+            node.private_ips,
+            []
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'e7cf186125f51f3d9511754a40dcd12c'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['boot_cdrom'],
+            None
+        )
+        self.assertEqual(
+            extra['boot_volume']['id'],
+            'bvol-1'
+        )
+        self.assertEqual(
+            extra['boot_volume']['href'],
+            (
+                '/cloudapi/v3/datacenters/dc-1'
+                '/volumes/bvol-1'
+            )
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['name'],
+            'Test Node Volume'
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['size'],
+            10
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['image'],
+            'bvol-img'
+        )
+        self.assertEqual(
+            extra['cpu_family'],
+            'AMD_OPTERON'
+        )
+
+        '''
+        Other miscellaneous
+        '''
+        self.assertEqual(
+            len(extra['entities']),
+            3
+        )
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
 
-        zone = type('ExProfitBricksAvailabilityZone', (object,),
-                    dict(name="ZONE_2"))
+    def test_ex_list_availability_zones(self):
 
-        update = self.driver.ex_update_node(node=node, ram=2048, cores=2, name="server002", availability_zone=zone)
+        zones = self.driver.ex_list_availability_zones()
+        self.assertEqual(len(zones), 3)
 
-        self.assertTrue(update)
+        zones_sorted = sorted(list(a.name for a in zones))
+        zones_expected = ['AUTO', 'ZONE_1', 'ZONE_2']
+        self.assertEqual(zones_sorted, zones_expected)
 
-    ''' Volume Function Tests
-    '''
     def test_list_volumes(self):
-        volumes = self.driver.list_volumes()
 
-        self.assertEqual(len(volumes), 4)
+        volumes = self.driver.list_volumes()
+        self.assertEqual(len(volumes), 3)
 
         volume = volumes[0]
-        self.assertEqual(volume.id, "453582cf-8d54-4ec8-bc0b-f9962f7fd232")
-        self.assertEqual(volume.name, "storage001")
-        self.assertEqual(volume.size, 50)
-        self.assertEqual(volume.extra['server_id'], "ebee7d83-912b-42f1-9b62-b953351a7e29")
-        self.assertEqual(volume.extra['provisioning_state'], NodeState.RUNNING)
-        self.assertEqual(volume.extra['creation_time'], "2014-07-15T03:19:38.252Z")
-        self.assertEqual(volume.extra['last_modification_time'], "2014-07-15T03:28:58.724Z")
-        self.assertEqual(volume.extra['image_id'], "d2f627c4-0289-11e4-9f63-52540066fee9")
-        self.assertEqual(volume.extra['image_name'], "CentOS-6-server-2014-07-01")
-        self.assertEqual(volume.extra['datacenter_id'], "06eac419-c2b3-4761-aeb9-10efdd2cf292")
+        extra = volume.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            volume.id,
+            'bvol-1'
+        )
+        self.assertEqual(
+            volume.name,
+            'Test Volume'
+        )
+        self.assertEqual(
+            volume.size,
+            10
+        )
+
+        '''
+        Extra
+        '''
+        self.assertEqual(
+            extra['provisioning_state'],
+            NodeState.RUNNING)
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-18T07:20:41Z'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '33f6b8d506e7ad756e8554b915f29c61'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T07:20:41Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test Volume'
+        )
+        self.assertEqual(
+            extra['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['size'],
+            10
+        )
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['image'],
+            'bvol-img'
+        )
+        self.assertEqual(
+            extra['image_password'],
+            None
+        )
+        self.assertEqual(
+            extra['ssh_keys'],
+            None
+        )
+        self.assertEqual(
+            extra['bus'],
+            'VIRTIO'
+        )
+        self.assertEqual(
+            extra['licence_type'],
+            'LINUX'
+        )
+        self.assertEqual(
+            extra['cpu_hot_plug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['nic_hot_unplug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['device_number'],
+            1
+        )
 
-    def test_create_volume(self):
-        datacenter = type('Datacenter', (object,),
-                          dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
-
-        image = type('NodeImage', (object,),
-                     dict(id="cd59b162-0289-11e4-9f63-52540066fee9"))
+    def test_ex_list_datacenters(self):
 
-        create = self.driver.create_volume(name="StackPointCloudStorage001",
-                                           size=50,
-                                           ex_datacenter=datacenter,
-                                           ex_image=image)
+        datacenters = self.driver.ex_list_datacenters()
+        self.assertEqual(len(datacenters), 1)
+
+        datacenter = datacenters[0]
+        extra = datacenter.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            datacenter.id,
+            'dc-1'
+        )
+        self.assertEqual(
+            datacenter.href,
+            '/cloudapi/v3/datacenters/dc-1'
+        )
+        self.assertEqual(
+            datacenter.name,
+            'Test One.'
+        )
+        self.assertEqual(
+            datacenter.version,
+            3
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test One.'
+        )
+        self.assertEqual(
+            extra['description'],
+            'A test data center'
+        )
+        self.assertEqual(
+            extra['location'],
+            'de/fra'
+        )
+        self.assertEqual(
+            extra['version'],
+            3
+        )
+        self.assertEqual(
+            extra['features'],
+            ['SSD', 'MULTIPLE_CPU']
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-14T07:24:59Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'bdddec2287cb7723e86ac088bf644606'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T15:27:25Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+        self.assertEqual(
+            extra['provisioning_state'],
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            len(extra['entities']),
+            4
+        )
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
+
+    def test_list_snapshots(self):
+
+        volume_snapshots = self.driver.list_snapshots()
+        self.assertEqual(len(volume_snapshots), 1)
+
+        snapshot = volume_snapshots[0]
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            snapshot.id,
+            'sshot'
+        )
+        self.assertEqual(
+            snapshot.size,
+            10
+        )
+        self.assertEqual(
+            snapshot.created,
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.state,
+            NodeState.RUNNING)
+        self.assertEqual(
+            snapshot.name,
+            'Balancer Testing 1 Storage-Snapshot-10/26/2016'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            snapshot.extra['name'],
+            'Balancer Testing 1 Storage-Snapshot-10/26/2016'
+        )
+        self.assertEqual(
+            snapshot.extra['description'],
+            (
+                'Created from \"Balancer Testing 1'
+                ' Storage\" in Data Center \"Snapshot\"'
+            )
+        )
+        self.assertEqual(
+            snapshot.extra['location'],
+            'us/las'
+        )
+        self.assertEqual(
+            snapshot.extra['size'],
+            10
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['licence_type'],
+            'LINUX'
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            snapshot.extra['created_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['etag'],
+            '01873262ac042b5f44ed33b4241225b4'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['state'],
+            'AVAILABLE'
+        )
 
-        self.assertTrue(create)
+    '''
+    Function tests for operations on volume snapshots
+    '''
 
-    def test_attach_volume_general(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+    def test_create_volume_snapshot(self):
+        volume = self.driver.ex_describe_volume(
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/vol-2'
+            )
+        )
+        snapshot = self.driver.create_volume_snapshot(volume=volume)
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            snapshot.id,
+            'sshot'
+        )
+        self.assertEqual(
+            snapshot.size,
+            10
+        )
+        self.assertEqual(
+            snapshot.created,
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.state,
+            NodeState.PENDING
+        )
+        self.assertEqual(
+            snapshot.name,
+            'Test Created Snapshot'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            snapshot.extra['name'],
+            'Test Created Snapshot'
+        )
+        self.assertEqual(
+            snapshot.extra['description'],
+            'Test Created Snapshot'
+        )
+        self.assertEqual(
+            snapshot.extra['location'],
+            'us/las'
+        )
+        self.assertEqual(
+            snapshot.extra['size'],
+            10
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_unplug'],
+            True
+        )
+
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['licence_type'],
+            'LINUX'
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            snapshot.extra['created_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['etag'],
+            '01873262ac042b5f44ed33b4241225b4'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['state'],
+            'BUSY'
+        )
+
+    def test_ex_describe_snapshot(self):
+        snapshot_w_href = self.driver.ex_describe_snapshot(
+            ex_href='/cloudapi/v3/snapshots/sshot'
+        )
+        snapshot_w_id = self.driver.ex_describe_snapshot(
+            ex_snapshot_id='sshot'
+        )
+        self._verify_snapshot(snapshot=snapshot_w_href)
+        self._verify_snapshot(snapshot=snapshot_w_id)
+
+    def _verify_snapshot(self, snapshot):
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            snapshot.id,
+            'sshot'
+        )
+        self.assertEqual(
+            snapshot.size,
+            10
+        )
+        self.assertEqual(
+            snapshot.created,
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.state,
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            snapshot.name,
+            'Test Snapshot'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            snapshot.extra['name'],
+            'Test Snapshot'
+        )
+        self.assertEqual(
+            snapshot.extra['description'],
+            'Test Snapshot'
+        )
+        self.assertEqual(
+            snapshot.extra['location'],
+            'us/las'
+        )
+        self.assertEqual(
+            snapshot.extra['size'],
+            10
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['nic_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            snapshot.extra['licence_type'],
+            'LINUX'
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            snapshot.extra['created_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['etag'],
+            '01873262ac042b5f44ed33b4241225b4'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_date'],
+            '2016-10-26T11:38:45Z'
+        )
+        self.assertEqual(
+            snapshot.extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            snapshot.extra['state'],
+            'AVAILABLE'
+        )
+
+    def test_ex_update_snapshot(self):
+        snapshot = self.driver.ex_describe_snapshot(
+            ex_href='/cloudapi/v3/snapshots/sshot'
+        )
+        updated = self.driver.ex_update_snapshot(
+            snapshot=snapshot,
+            name='Updated snapshot',
+            description='Upated snapshot',
+            cpu_hot_unplug=True
+        )
+
+        self.assertEqual(
+            updated.name,
+            'Updated snapshot'
+        )
+        self.assertEqual(
+            updated.extra['description'],
+            'Updated snapshot'
+        )
+        self.assertEqual(
+            updated.extra['cpu_hot_unplug'],
+            True
+        )
+
+    def test_destroy_volume_snapshot(self):
+        snapshot = self.driver.ex_describe_snapshot(
+            ex_href='/cloudapi/v3/snapshots/sshot'
+        )
+        destroyed = self.driver.destroy_volume_snapshot(snapshot)
+        self.assertTrue(destroyed)
 
-        node = type('Node', (object,),
-                    dict(id="cd59b162-0289-11e4-9f63-52540066fee9"))
+    '''
+    Function tests for operations on nodes (servers)
+    '''
 
-        attach = self.driver.attach_volume(node=node,
-                                           volume=volume,
-                                           device=None, ex_bus_type=None)
+    def test_reboot_node(self):
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/dc-1'
+                '/servers/srv-1'
+            )
+        )
+        rebooted = self.driver.reboot_node(node=node)
+        self.assertTrue(rebooted)
+
+    def test_create_node(self):
+        image = self.driver.ex_describe_image(
+            ex_href='/cloudapi/v3/images/img-2'
+        )
+        datacenter = self.driver.ex_describe_datacenter(
+            ex_href='/cloudapi/v3/datacenters/dc-1'
+        )
+        sizes = self.driver.list_sizes()
 
-        self.assertTrue(attach)
+        with self.assertRaises(ValueError):
+            'Raises value error if no size or ex_ram'
+            self.driver.create_node(
+                name='Test',
+                image=image,
+                ex_disk=40,
+                ex_cores=1
+            )
+
+        with self.assertRaises(ValueError):
+            'Raises value error if no size or ex_cores'
+            self.driver.create_node(
+                name='Test',
+                image=image,
+                ex_disk=40,
+                ex_ram=1024
+            )
+
+        with self.assertRaises(ValueError):
+            'Raises value error if no size or ex_disk'
+            self.driver.create_node(
+                name='Test',
+                image=image,
+                ex_cores=2,
+                ex_ram=1024
+            )
+
+        with self.assertRaises(ValueError):
+            'Raises value error if no ssh keys or password'
+            self.driver.create_node(
+                name='Test',
+                image=image,
+                size=sizes[1],
+                datacenter=datacenter
+            )
+
+        node = self.driver.create_node(
+            name='Test',
+            image=image,
+            size=sizes[1],
+            ex_password='dummy1234',
+            datacenter=datacenter
+        )
+
+        extra = node.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            node.id,
+            'srv-2'
+        )
+        self.assertEqual(
+            node.name,
+            'Test'
+        )
+        self.assertEqual(
+            node.state,
+            NodeState.UNKNOWN
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T13:25:19Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '9bea2412ac556b402a07260fc0d1603f'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T13:25:19Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test'
+        )
+        self.assertEqual(
+            extra['cores'],
+            1
+        )
+        self.assertEqual(
+            extra['ram'],
+            512
+        )
+        self.assertEqual(
+            extra['availability_zone'],
+            'ZONE_1'
+        )
+        self.assertEqual(
+            extra['vm_state'],
+            None
+        )
+
+        self.assertEqual(
+            extra['boot_cdrom'],
+            None
+        )
+        self.assertEqual(
+            extra['boot_volume'],
+            None
+        )
+        self.assertEqual(
+            extra['cpu_family'],
+            'INTEL_XEON'
+        )
+
+        '''
+        Extra entities
+        '''
+        self.assertEqual(
+            len(extra['entities']['volumes']['items']),
+            1
+        )
 
-    def test_attach_volume_device_defined(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+    def test_destroy_node(self):
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        destroyed = self.driver.destroy_node(
+            node=node,
+            ex_remove_attached_disks=False
+        )
+        self.assertTrue(destroyed)
+
+    def test_ex_list_attached_volumes(self):
+
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/servers/'
+                'srv-1'
+            )
+        )
+
+        attached_volumes = self.driver.ex_list_attached_volumes(node)
+        self.assertEqual(len(attached_volumes), 3)
+
+    def test_attach_volume(self):
+
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        volume = self.driver.ex_describe_volume(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/vol-2'
+            )
+        )
+
+        attached = self.driver.attach_volume(node=node, volume=volume)
+        extra = attached.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            attached.id,
+            'vol-2'
+        )
+        self.assertEqual(
+            attached.name,
+            'Updated storage name'
+        )
+        self.assertEqual(
+            attached.size,
+            40
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T13:13:36Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'c1800ce349033f9cd2c095ea1ea4976a'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T13:47:52Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Updated storage name'
+        )
+        self.assertEqual(
+            extra['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['size'],
+            40
+        )
+        self.assertEqual(
+            extra['image'],
+            'bvol-img'
+        )
+
+        self.assertEqual(
+            extra['image_password'],
+            None
+        )
+        self.assertEqual(
+            extra['ssh_keys'],
+            None
+        )
+        self.assertEqual(
+            extra['bus'],
+            'VIRTIO'
+        )
+        self.assertEqual(
+            extra['licence_type'],
+            'LINUX'
+        )
+        self.assertEqual(
+            extra['cpu_hot_plug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['nic_hot_unplug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['device_number'],
+            3
+        )
+
+        self.assertNotIn(
+            'availability_zone',
+            extra
+        )
 
-        node = type('Node', (object,),
-                    dict(id="cd59b162-0289-11e4-9f63-52540066fee9"))
+    def test_detach_volume(self):
 
-        attach = self.driver.attach_volume(node=node, volume=volume, device=1, ex_bus_type=None)
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        volume = self.driver.ex_describe_volume(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/vol-2'
+            )
+        )
+        detached = self.driver.detach_volume(
+            node=node,
+            volume=volume
+        )
+        self.assertTrue(detached)
 
-        self.assertTrue(attach)
+    def test_ex_stop_node(self):
 
-    def test_attach_volume_bus_type_defined(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        stopped = self.driver.ex_stop_node(node)
+        self.assertTrue(stopped)
 
-        node = type('Node', (object,),
-                    dict(id="cd59b162-0289-11e4-9f63-52540066fee9"))
+    def test_ex_start_node(self):
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        started = self.driver.ex_start_node(node)
+        self.assertTrue(started)
 
-        attach = self.driver.attach_volume(node=node,
-                                           volume=volume,
-                                           device=None,
-                                           ex_bus_type="IDE")
+    def test_ex_describe_node(self):
+        node_w_href = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        node_w_id = self.driver.ex_describe_node(
+            ex_datacenter_id='dc-1',
+            ex_node_id='srv-1'
+        )
+        self._verify_node(node=node_w_href)
+        self._verify_node(node=node_w_id)
+
+    def _verify_node(self, node):
+        extra = node.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            node.id,
+            'srv-1'
+        )
+        self.assertEqual(
+            node.name,
+            'A test node'
+        )
+        self.assertEqual(
+            node.state,
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            node.public_ips,
+            []
+        )
+        self.assertEqual(
+            node.private_ips,
+            []
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'e7cf186125f51f3d9511754a40dcd12c')
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['boot_cdrom'],
+            None
+        )
+        self.assertEqual(
+            extra['boot_volume']['id'],
+            'bvol-1'
+        )
+        self.assertEqual(
+            extra['boot_volume']['href'],
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/bvol-1'
+            )
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['name'],
+            'A test node boot volume'
+        )
+
+        self.assertEqual(
+            extra['boot_volume']['properties']['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['size'],
+            10
+        )
+        self.assertEqual(
+            extra['boot_volume']['properties']['image'],
+            'bvol-img'
+        )
+        self.assertEqual(
+            extra['cpu_family'],
+            'AMD_OPTERON'
+        )
+
+        '''
+        Other miscellaneous
+        '''
+        self.assertEqual(
+            len(extra['entities']),
+            3
+        )
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
 
-        self.assertTrue(attach)
+    def test_ex_update_node(self):
 
-    def test_attach_volume_options_defined(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+        node = self.driver.ex_describe_node(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        zones = self.driver.ex_list_availability_zones()
+        updated = self.driver.ex_update_node(
+            node=node,
+            name='Test update',
+            cores=4,
+            ram=4096,
+            availability_zone=zones[0],
+            ex_cpu_family='INTEL_XEON'
+        )
+
+        extra = updated.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            updated.id,
+            'srv-1'
+        )
+        self.assertEqual(
+            updated.name,
+            'A test node'
+        )
+        self.assertEqual(
+            updated.state,
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            updated.public_ips,
+            []
+        )
+        self.assertEqual(
+            updated.private_ips,
+            []
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'e7cf186125f51f3d9511754a40dcd12c'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T07:28:05Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['boot_cdrom'],
+            None
+        )
+        self.assertEqual(
+            extra['boot_volume']['id'],
+            'bvol-1'
+        )
+        self.assertEqual(
+            extra['boot_volume']['href'],
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/bvol-1'
+            )
+        )
+        self.assertEqual(
+            extra['cpu_family'],
+            'AMD_OPTERON'
+        )
 
-        node = type('Node', (object,),
-                    dict(id="cd59b162-0289-11e4-9f63-52540066fee9"))
+    '''
+    Function tests for operations on volumes
+    '''
 
-        attach = self.driver.attach_volume(node=node, volume=volume,
-                                           device=1, ex_bus_type="IDE")
+    def test_create_volume(self):
 
-        self.assertTrue(attach)
+        datacenter = self.driver.ex_describe_datacenter(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1'
+            )
+        )
+        image = self.driver.ex_describe_image(
+            ex_href='/cloudapi/v3/images/img-2'
+        )
+        created = self.driver.create_volume(
+            size=30,
+            name='Test volume',
+            ex_type='HDD',
+            ex_bus_type='IDE',
+            ex_datacenter=datacenter,
+            image=image,
+            ex_password='dummyP8ssw0rdl33t'
+        )
+
+        self.assertTrue(created)
 
-    def test_detach_volume(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476",
-                           extra={'server_id': "cd59b162-0289-11e4-9f63-52540066fee9"}
-                           ))
+    def test_destroy_volume(self):
 
-        attach = self.driver.detach_volume(volume=volume)
+        volume = self.driver.ex_describe_volume(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/volumes/'
+                'vol-2'
+            )
+        )
+        destroyed = self.driver.destroy_volume(volume=volume)
+
+        self.assertTrue(destroyed)
+
+    def test_ex_update_volume(self):
+
+        volume = self.driver.ex_describe_volume(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/vol-2'
+            )
+
+        )
+        updated = self.driver.ex_update_volume(
+            volume=volume,
+            ex_storage_name='Updated volume',
+            size=48,
+            ex_bus_type='VIRTIO'
+        )
+
+        extra = updated.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            updated.id,
+            'vol-2'
+        )
+        self.assertEqual(
+            updated.name,
+            'Updated storage name'
+        )
+        self.assertEqual(
+            updated.size,
+            40
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T13:13:36Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'c1800ce349033f9cd2c095ea1ea4976a'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T13:47:52Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Updated storage name'
+        )
+        self.assertEqual(
+            extra['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['size'],
+            40
+        )
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['image'],
+            'bvol-img'
+        )
+
+        self.assertEqual(
+            extra['image_password'],
+            None
+        )
+        self.assertEqual(
+            extra['ssh_keys'],
+            None
+        )
+        self.assertEqual(
+            extra['bus'],
+            'VIRTIO'
+        )
+        self.assertEqual(
+            extra['licence_type'],
+            'LINUX'
+        )
+        self.assertEqual(
+            extra['cpu_hot_plug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['nic_hot_unplug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['device_number'],
+            3
+        )
+
+        return {}
 
-        self.assertTrue(attach)
+    def test_ex_describe_volume(self):
+        volume_w_href = self.driver.ex_describe_volume(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'volumes/vol-2'
+            )
+        )
+        volume_w_id = self.driver.ex_describe_volume(
+            ex_datacenter_id='dc-1',
+            ex_volume_id='vol-2'
+        )
+        self._verify_volume(volume=volume_w_href)
+        self._verify_volume(volume=volume_w_id)
+
+    def _verify_volume(self, volume):
+        extra = volume.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            volume.id,
+            'vol-2'
+        )
+        self.assertEqual(
+            volume.name,
+            'Updated storage name'
+        )
+        self.assertEqual(
+            volume.size,
+            40
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T13:13:36Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'c1800ce349033f9cd2c095ea1ea4976a'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T13:47:52Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Updated storage name'
+        )
+        self.assertEqual(
+            extra['type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['size'],
+            40
+        )
+        self.assertEqual(
+            extra['availability_zone'],
+            'AUTO'
+        )
+        self.assertEqual(
+            extra['image'],
+            'bvol-img'
+        )
+
+        self.assertEqual(
+            extra['image_password'],
+            None
+        )
+        self.assertEqual(
+            extra['ssh_keys'],
+            None
+        )
+        self.assertEqual(
+            extra['bus'],
+            'VIRTIO'
+        )
+        self.assertEqual(
+            extra['licence_type'],
+            'LINUX'
+        )
+        self.assertEqual(
+            extra['cpu_hot_plug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['nic_hot_unplug'],
+            True
+        )
+
+        self.assertEqual(
+            extra['disc_virtio_hot_plug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_virtio_hot_unplug'],
+            True
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['device_number'],
+            3
+        )
+
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
 
-    def test_destroy_volume(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+    '''
+    Function tests for operations on data centers
+    '''
 
-        destroy = self.driver.destroy_volume(volume=volume)
+    def test_ex_create_datacenter(self):
+        location = self.driver.ex_describe_location(ex_location_id='de/fkb')
+        datacenter = self.driver.ex_create_datacenter(
+            name='Test Data Center',
+            location=location,
+            description='Test Data Center.'
+        )
+
+        extra = datacenter.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            datacenter.id,
+            'dc-1'
+        )
+        self.assertEqual(
+            datacenter.href,
+            '/cloudapi/v3/datacenters/dc-1'
+        )
+        self.assertEqual(
+            datacenter.name,
+            'Test Data Center'
+        )
+        self.assertEqual(
+            datacenter.version,
+            None
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-18T17:20:56Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'c2d3d4d9bbdc0fff7d3c5c3864a68a46'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T17:20:56Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test Data Center'
+        )
+        self.assertEqual(
+            extra['description'],
+            'Test Data Center.'
+        )
+        self.assertEqual(
+            extra['location'],
+            'us/las'
+        )
+        self.assertEqual(
+            extra['version'],
+            None
+        )
+        self.assertEqual(
+            extra['features'],
+            []
+        )
+
+        '''
+        Miscellaneous properties
+        '''
+        self.assertNotIn(
+            'entities',
+            extra
+        )
+        self.assertEqual(
+            extra['provisioning_state'],
+            NodeState.PENDING
+        )
 
-        self.assertTrue(destroy)
+    def test_ex_destroy_datacenter(self):
 
-    def test_update_volume(self):
-        volume = type('StorageVolume', (object,),
-                      dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
+        datacenter = self.driver.ex_describe_datacenter(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1'
+            )
+        )
+        destroyed = self.driver.ex_destroy_datacenter(
+            datacenter=datacenter
+        )
+        self.assertTrue(destroyed)
 
-        destroy = self.driver.ex_update_volume(volume=volume)
+    def test_ex_describe_datacenter(self):
+        datacenter_w_href = self.driver.ex_describe_datacenter(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1'
+            )
+        )
+        datacenter_w_id = self.driver.ex_describe_datacenter(
+            ex_datacenter_id='dc-1'
+        )
+        self._verify_datacenter(datacenter=datacenter_w_href)
+        self._verify_datacenter(datacenter=datacenter_w_id)
+
+    def _verify_datacenter(self, datacenter):
+        extra = datacenter.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            datacenter.id,
+            'dc-1'
+        )
+        self.assertEqual(
+            datacenter.href,
+            '/cloudapi/v3/datacenters/dc-1'
+        )
+        self.assertEqual(
+            datacenter.name,
+            'Test Data Center'
+        )
+        self.assertEqual(
+            datacenter.version,
+            35
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T11:33:11Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '53b215b8ec0356a649955dab019845a4'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T15:13:44Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test Data Center'
+        )
+        self.assertEqual(
+            extra['description'],
+            'This is a test data center.'
+        )
+        self.assertEqual(
+            extra['location'],
+            'de/fkb'
+        )
+        self.assertEqual(
+            extra['version'],
+            35
+        )
+        self.assertEqual(
+            extra['features'],
+            ['SSD', 'MULTIPLE_CPU']
+        )
+
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
+        self.assertEqual(
+            extra['provisioning_state'],
+            NodeState.RUNNING
+        )
+        self.assertEqual(
+            len(extra['entities']),
+            4
+        )
 
-        self.assertTrue(destroy)
+    def test_ex_rename_datacenter(self):
 
-    def test_ex_describe_volume(self):
-        describe = self.driver.ex_describe_volume(volume_id="8669a69f-2274-4520-b51e-dbdf3986a476")
+        datacenter = self.driver.ex_describe_datacenter(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1'
+            )
+        )
+        renamed = self.driver.ex_rename_datacenter(
+            datacenter=datacenter,
+            name='Renamed data center'
+        )
+        extra = renamed.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            renamed.id,
+            'dc-1'
+        )
+        self.assertEqual(
+            renamed.href,
+            '/cloudapi/v3/datacenters/dc-1'
+        )
+        self.assertEqual(
+            renamed.name,
+            'Test Data Center'
+        )
+        self.assertEqual(
+            renamed.version,
+            35
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T11:33:11Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '53b215b8ec0356a649955dab019845a4'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-18T15:13:44Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.test'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test Data Center'
+        )
+        self.assertEqual(
+            extra['description'],
+            'This is a test data center.'
+        )
+        self.assertEqual(
+            extra['location'],
+            'de/fkb'
+        )
+        self.assertEqual(
+            extra['version'],
+            35
+        )
+        self.assertEqual(
+            extra['features'],
+            ['SSD', 'MULTIPLE_CPU']
+        )
+
+        self.assertNotIn(
+            'status_url',
+            extra
+        )
+        self.assertEqual(
+            extra['provisioning_state'],
+            NodeState.PENDING
+        )
+        self.assertEqual(
+            len(extra['entities']),
+            4
+        )
 
-        self.assertEqual(describe.id, "00d0b9e7-e016-456f-85a0-517aa9a34bf5")
-        self.assertEqual(describe.size, 50)
-        self.assertEqual(describe.name, "StackPointCloud-Volume")
-        self.assertEqual(describe.extra['provisioning_state'], NodeState.RUNNING)
+    '''
+    Function tests for operations on images
+    '''
+    def test_ex_describe_image(self):
+        image_w_href = self.driver.ex_describe_image(
+            ex_href=(
+                '/cloudapi/v3/images/'
+                'img-2'
+            )
+        )
+        image_w_id = self.driver.ex_describe_image(
+            ex_image_id='img-2'
+        )
+        self._verify_image(image=image_w_href)
+        self._verify_image(image=image_w_id)
+
+    def _verify_image(self, image):
+        extra = image.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            image.id,
+            'img-2'
+        )
+        self.assertEqual(
+            image.name,
+            'vivid-server-cloudimg-amd64-disk1.img'
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2015-10-09T12:06:34Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'bbf76112358af2fc5dd1bf21de8988db'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2015-11-11T15:23:20Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'vivid-server-cloudimg-amd64-disk1.img'
+        )
+        self.assertEqual(
+            extra['description'],
+            None
+        )
+        self.assertEqual(
+            extra['location'],
+            'de/fkb'
+        )
+        self.assertEqual(
+            extra['size'],
+            2
+        )
+        self.assertEqual(
+            extra['cpu_hot_plug'],
+            False
+        )
+
+        self.assertEqual(
+            extra['cpu_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['ram_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['nic_hot_unplug'],
+            False
+        )
+
+        self.assertEqual(
+            extra['disc_virtio_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_virtio_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_plug'],
+            False
+        )
+        self.assertEqual(
+            extra['disc_scsi_hot_unplug'],
+            False
+        )
+        self.assertEqual(
+            extra['licence_type'],
+            'UNKNOWN'
+        )
+
+        self.assertEqual(
+            extra['image_type'],
+            'HDD'
+        )
+        self.assertEqual(
+            extra['public'],
+            False
+        )
+        self.assertEqual(
+            extra['href'],
+            '/cloudapi/v3/images/img-2'
+        )
+
+    def test_ex_update_image(self):
+        image = self.driver.ex_describe_image(
+            ex_href=(
+                '/cloudapi/v3/images/'
+                'img-2'
+            )
+        )
+        updated = self.driver.ex_update_image(
+            image=image,
+            name='my-updated-image.img'
+        )
+        extra = updated.extra
+
+        self.assertEqual(
+            updated.name,
+            'my-updated-image.img'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-11-11T15:23:20Z'
+        )
+
+    def test_ex_delete_image(self):
+        image = self.driver.ex_describe_image(
+            ex_href=(
+                '/cloudapi/v3/images/'
+                'img-2'
+            )
+        )
+        deleted = self.driver.ex_delete_image(image)
+        self.assertTrue(deleted)
 
-    ''' Image Function Tests
     '''
-    def test_list_images(self):
-        images = self.driver.list_images()
+    Function tests for operations on network interfaces
+    '''
+
+    def test_ex_list_network_interfaces(self):
+
+        network_interfaces = self.driver.ex_list_network_interfaces()
+        self.assertEqual(
+            len(network_interfaces),
+            4
+        )
+
+        network_interface = network_interfaces[0]
+        extra = network_interface.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            network_interface.id,
+            'nic-1'
+        )
+        self.assertEqual(
+            network_interface.name,
+            'Test network interface'
+        )
+        self.assertEqual(
+            network_interface.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/servers/'
+                's-3/nics/'
+                'nic-1'
+            )
+        )
+        self.assertEqual(
+            network_interface.state,
+            NodeState.RUNNING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T15:46:38Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'dbd8216137cf0ec9951170f93fa8fa53'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T18:19:43Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test network interface'
+        )
+        self.assertEqual(
+            extra['mac'],
+            '02:01:0b:9d:4d:ce'
+        )
+        self.assertEqual(
+            extra['ips'],
+            ['10.15.124.11']
+        )
+        self.assertEqual(
+            extra['dhcp'],
+            False
+        )
+        self.assertEqual(
+            extra['lan'],
+            2
+        )
+        self.assertEqual(
+            extra['firewall_active'],
+            True
+        )
+        self.assertEqual(
+            extra['nat'],
+            False
+        )
+
+    def test_ex_describe_network_interface(self):
+        nic_w_href = self.driver.ex_describe_network_interface(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3'
+                '/nics/nic-2'
+            )
+        )
+        nic_w_id = self.driver.ex_describe_network_interface(
+            ex_datacenter_id='dc-1',
+            ex_server_id='s-3',
+            ex_nic_id='nic-2'
+        )
+        self._verify_network_interface(network_interface=nic_w_href)
+        self._verify_network_interface(network_interface=nic_w_id)
+
+    def _verify_network_interface(self, network_interface):
+        extra = network_interface.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            network_interface.id,
+            'nic-2'
+        )
+        self.assertEqual(
+            network_interface.name,
+            'Updated from LibCloud'
+        )
+        self.assertEqual(
+            network_interface.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2'
+            )
+        )
+        self.assertEqual(
+            network_interface.state,
+            NodeState.RUNNING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-17T15:46:38Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'dbd8216137cf0ec9951170f93fa8fa53'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-17T18:19:43Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Updated from LibCloud'
+        )
+        self.assertEqual(
+            extra['mac'],
+            '02:01:0b:9d:4d:ce'
+        )
+        self.assertEqual(
+            extra['ips'],
+            ['10.15.124.11']
+        )
+        self.assertEqual(
+            extra['dhcp'],
+            False
+        )
+        self.assertEqual(
+            extra['lan'],
+            2
+        )
+        self.assertEqual(
+            extra['firewall_active'],
+            True
+        )
+        self.assertEqual(
+            extra['nat'],
+            False
+        )
+
+        '''
+        Miscellaneous
+        '''
+        self.assertTrue(
+            len(extra['entities']),
+            1
+        )
+
+    def test_ex_create_network_interface(self):
 
-        self.assertEqual(len(images), 3)
+        node = self.driver.ex_describe_node(
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+            )
+        )
+        network_interface = self.driver.ex_create_network_interface(
+            node=node,
+            lan_id=1,
+            dhcp_active=True,
+            nic_name='Creating a test network interface.'
+        )
+        extra = network_interface.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            network_interface.id,
+            'nic-2'
+        )
+        self.assertEqual(
+            network_interface.name,
+            'Creating a test network interface.'
+        )
+        self.assertEqual(
+            network_interface.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/srv-1'
+                '/nics/nic-2'
+            )
+        )
+        self.assertEqual(
+            network_interface.state,
+            NodeState.PENDING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T08:18:50Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '8679142b0b1b70c8b8c09a8b31e6ded9'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T08:18:50Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Creating a test network interface.'
+        )
+        self.assertEqual(
+            extra['mac'],
+            None
+        )
+        self.assertEqual(
+            extra['ips'],
+            []
+        )
+        self.assertEqual(
+            extra['dhcp'],
+            True
+        )
+        self.assertEqual(
+            extra['lan'],
+            1
+        )
+        self.assertEqual(
+            extra['firewall_active'],
+            None
+        )
+        self.assertEqual(
+            extra['nat'],
+            None
+        )
+
+    def test_ex_update_network_interface(self):
 
-        image = images[0]
-        self.assertEqual(image.extra['cpu_hotpluggable'], "false")
-        self.assertEqual(image.id, "03b6c3e7-f2ad-11e3-a036-52540066fee9")
-        self.assertEqual(image.name, "windows-2012-r2-server-2014-06")
-        self.assertEqual(image.extra['image_size'], "11264")
-        self.assertEqual(image.extra['image_type'], "HDD")
-        self.assertEqual(image.extra['memory_hotpluggable'], "false")
-        self.assertEqual(image.extra['os_type'], "WINDOWS")
-        self.assertEqual(image.extra['public'], "true")
-        self.assertEqual(image.extra['location'], None)
-        self.assertEqual(image.extra['writeable'], "true")
+        network_interface = self.driver.ex_describe_network_interface(
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3'
+                '/nics/nic-2'
+            )
+        )
+        updated = self.driver.ex_update_network_interface(
+            network_interface=network_interface,
+            name='New network interface', dhcp_active=False
+        )
+
+        extra = updated.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            updated.id,
+            'nic-2'
+        )
+        self.assertEqual(
+            updated.name,
+            'Updated from LibCloud'
+        )
+        self.assertEqual(
+            updated.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2'
+            )
+        )
+        self.assertEqual(
+            updated.state,
+            NodeState.PENDING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T08:18:55Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '56f8d8bbdc84faad4188f647a49a565b'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T09:44:59Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Updated from LibCloud'
+        )
+        self.assertEqual(
+            extra['mac'],
+            '02:01:68:c1:e8:88'
+        )
+        self.assertEqual(
+            extra['ips'],
+            ['11.12.13.14']
+        )
+        self.assertEqual(
+            extra['dhcp'],
+            True
+        )
+        self.assertEqual(
+            extra['lan'],
+            1
+        )
+        self.assertEqual(
+            extra['firewall_active'],
+            False
+        )
+        self.assertEqual(
+            extra['nat'],
+            False
+        )
+
+        self.assertTrue(updated)
+
+    def test_ex_destroy_network_interface(self):
+
+        network_interface = self.driver.ex_describe_network_interface(
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3'
+                '/nics/nic-2'
+            )
+        )
+        destroyed = self.driver.ex_destroy_network_interface(
+            network_interface=network_interface
+        )
+
+        self.assertTrue(destroyed)
+
+    def test_ex_set_inet_access(self):
+        network_interface = self.driver.ex_describe_network_interface(
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3'
+                '/nics/nic-2'
+            )
+        )
+        updated = self.driver.ex_set_inet_access(
+            network_interface=network_interface,
+            internet_access=False)
+
+        self.assertTrue(updated)
+
+        return {}
 
-    ''' Datacenter Function Tests
     '''
-    def test_ex_create_datacenter(self):
-        datacenter = self.driver.ex_create_datacenter(name="StackPointCloud",
-                                                      location="us/la")
+    Function tests for operations on locations
+    '''
 
-        self.assertEqual(datacenter.id, '0c793dd1-d4cd-4141-86f3-8b1a24b2d604')
-        self.assertEqual(datacenter.extra['location'], 'us/las')
-        self.assertEqual(datacenter.version, '1')
+    def test_ex_describe_location(self):
+        location_w_href = self.driver.ex_describe_location(
+            ex_href=(
+                '/cloudapi/v3/locations/de/fkb'
+            )
+        )
+        location_w_id = self.driver.ex_describe_location(
+            ex_location_id='de/fkb'
+        )
+        self._verify_location(location=location_w_href)
+        self._verify_location(location=location_w_id)
+
+    def _verify_location(self, location):
+        self.assertEqual(
+            location.id,
+            'de/fkb'
+        )
+        self.assertEqual(
+            location.name,
+            'karlsruhe'
+        )
+        self.assertEqual(
+            location.country,
+            'de'
+        )
 
-    def test_ex_destroy_datacenter(self):
-        datacenter = type('Datacenter', (object,),
-                          dict(id="8669a69f-2274-4520-b51e-dbdf3986a476"))
-        destroy = self.driver.ex_destroy_datacenter(datacenter=datacenter)
+    '''
+    Function tests for operations on firewall rules
+    '''
 
-        self.assertTrue(destroy)
+    def test_ex_list_firewall_rules(self):
+        network_interface = self.driver.ex_describe_network_interface(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2'
+            )
+        )
+        firewall_rules = self.driver.ex_list_firewall_rules(network_interface)
+        self.assertEqual(
+            len(firewall_rules),
+            3
+        )
+
+        firewall_rule = firewall_rules[0]
+        extra = firewall_rule.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            firewall_rule.id,
+            'fwr-1'
+        )
+        self.assertEqual(
+            firewall_rule.name,
+            'Test updated firewall rule'
+        )
+        self.assertEqual(
+            firewall_rule.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2/'
+                'firewallrules/fwr-1'
+            )
+        )
+        self.assertEqual(
+            firewall_rule.state,
+            NodeState.RUNNING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T11:08:10Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            'b91a2e082a7422dafb79d84a07fb2a28'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T11:19:04Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test updated firewall rule'
+        )
+        self.assertEqual(
+            extra['protocol'],
+            'TCP'
+        )
+        self.assertEqual(
+            extra['source_mac'],
+            None
+        )
+        self.assertEqual(
+            extra['source_ip'],
+            None
+        )
+        self.assertEqual(
+            extra['target_ip'],
+            None
+        )
+
+        self.assertEqual(
+            extra['icmp_code'],
+            None
+        )
+        self.assertEqual(
+            extra['icmp_type'],
+            None
+        )
+        self.assertEqual(
+            extra['port_range_start'],
+            80
+        )
+        self.assertEqual(
+            extra['port_range_end'],
+            80
+        )
+
+    def test_ex_describe_firewall_rule(self):
+        firewall_rule_w_href = self.driver.ex_describe_firewall_rule(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/servers/'
+                's-3/nics/'
+                'nic-2/firewallrules'
+                '/fw2'
+            )
+        )
+        firewall_rule_w_id = self.driver.ex_describe_firewall_rule(
+            ex_datacenter_id='dc-1',
+            ex_server_id='s-3',
+            ex_nic_id='nic-2',
+            ex_firewall_rule_id='fw2'
+        )
+        self._verify_firewall_rule(firewall_rule=firewall_rule_w_href)
+        self._verify_firewall_rule(firewall_rule=firewall_rule_w_id)
+
+    def _verify_firewall_rule(self, firewall_rule):
+        extra = firewall_rule.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            firewall_rule.id,
+            'fw2'
+        )
+        self.assertEqual(
+            firewall_rule.name,
+            'HTTPs (SSL)'
+        )
+        self.assertEqual(
+            firewall_rule.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/servers/'
+                's-3/nics/'
+                'nic-2/'
+                'firewallrules/fw2'
+            )
+        )
+        self.assertEqual(
+            firewall_rule.state,
+            NodeState.RUNNING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T09:55:10Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '00bb5b86562db1ed19ca38697e485160'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T09:55:10Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'AVAILABLE'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'HTTPs (SSL)'
+        )
+        self.assertEqual(
+            extra['protocol'],
+            'TCP'
+        )
+        self.assertEqual(
+            extra['source_mac'],
+            None
+        )
+        self.assertEqual(
+            extra['source_ip'],
+            None
+        )
+        self.assertEqual(
+            extra['target_ip'],
+            None
+        )
+
+        self.assertEqual(
+            extra['icmp_code'],
+            None
+        )
+        self.assertEqual(
+            extra['icmp_type'],
+            None
+        )
+        self.assertEqual(
+            extra['port_range_start'],
+            443
+        )
+        self.assertEqual(
+            extra['port_range_end'],
+            443
+        )
+
+    def test_ex_create_firewall_rule(self):
+
+        network_interface = self.driver.ex_describe_network_interface(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2'
+            )
+        )
+
+        firewall_rule = self.driver.ex_create_firewall_rule(
+            network_interface=network_interface,
+            protocol='TCP',
+            name='Test created firewall rule',
+            port_range_start=80,
+            port_range_end=80
+        )
+
+        extra = firewall_rule.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            firewall_rule.id,
+            'fwr-1'
+        )
+        self.assertEqual(
+            firewall_rule.name,
+            'Test created firewall rule'
+        )
+        self.assertEqual(
+            firewall_rule.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2/'
+                'firewallrules/fwr-1'
+            )
+        )
+        self.assertEqual(
+            firewall_rule.state,
+            NodeState.PENDING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T11:08:04Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '2a21551ba4adf85d9fb04b05a6938bcc'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T11:08:04Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'Test created firewall rule'
+        )
+        self.assertEqual(
+            extra['protocol'],
+            'TCP'
+        )
+        self.assertEqual(
+            extra['source_mac'],
+            None
+        )
+        self.assertEqual(
+            extra['source_ip'],
+            None
+        )
+        self.assertEqual(
+            extra['target_ip'],
+            None
+        )
+
+        self.assertEqual(
+            extra['icmp_code'],
+            None
+        )
+        self.assertEqual(
+            extra['icmp_type'],
+            None
+        )
+        self.assertEqual(
+            extra['port_range_start'],
+            80
+        )
+        self.assertEqual(
+            extra['port_range_end'],
+            80
+        )
+
+    def test_ex_update_firewall_rule(self):
+
+        firewall_rule = self.driver.ex_describe_firewall_rule(
+            ex_href=(
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3/'
+                'nics/nic-2/'
+                'firewallrules/fw2'
+            )
+        )
+        updated = self.driver.ex_update_firewall_rule(
+            firewall_rule=firewall_rule,
+            name='Test updated firewall rule',
+            port_range_start=8080,
+            port_range_end=8080
+        )
+
+        extra = updated.extra
+
+        '''
+        Standard properties
+        '''
+        self.assertEqual(
+            updated.id,
+            'fw2'
+        )
+        self.assertEqual(
+            updated.name,
+            'HTTPs (SSL)'
+        )
+        self.assertEqual(
+            updated.href,
+            (
+                '/cloudapi/v3/datacenters/'
+                'dc-1/'
+                'servers/s-3'
+                '/nics/nic-2/'
+                'firewallrules/fw2'
+            )
+        )
+        self.assertEqual(
+            updated.state,
+            NodeState.PENDING
+        )
+
+        '''
+        Extra metadata
+        '''
+        self.assertEqual(
+            extra['created_date'],
+            '2016-10-19T09:55:10Z'
+        )
+        self.assertEqual(
+            extra['created_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['etag'],
+            '00bb5b86562db1ed19ca38697e485160'
+        )
+        self.assertEqual(
+            extra['last_modified_date'],
+            '2016-10-19T09:55:10Z'
+        )
+        self.assertEqual(
+            extra['last_modified_by'],
+            'test@test.te'
+        )
+        self.assertEqual(
+            extra['state'],
+            'BUSY'
+        )
+
+        '''
+        Extra properties
+        '''
+        self.assertEqual(
+            extra['name'],
+            'HTTPs (SSL)'
+        )
+        self.assertEqual(
+            extra['protocol'],
+            'TCP'
+        )
+        self.assertEqual(
+            extra['source_mac'],
+            None
+        )
+        self.assertEqual(
+            extra['source_ip'],
+            None
+        )
+     

<TRUNCATED>

[4/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/attach_volume.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/attach_volume.json b/libcloud/test/compute/fixtures/profitbricks/attach_volume.json
new file mode 100644
index 0000000..eda9a22
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/attach_volume.json
@@ -0,0 +1,34 @@
+{
+    "id" : "vol-2",
+    "type" : "volume",
+    "href" : "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+    "metadata" : {
+        "createdDate" : "2016-10-17T13:13:36Z",
+        "createdBy" : "test@test.te",
+        "etag" : "c1800ce349033f9cd2c095ea1ea4976a",
+        "lastModifiedDate" : "2016-10-17T13:47:52Z",
+        "lastModifiedBy" : "test@test.te",
+        "state" : "BUSY"
+    },
+    "properties" : {
+        "name" : "Updated storage name",
+        "type" : "HDD",
+        "size" : 40,
+        "image" : "bvol-img",
+        "imagePassword" : null,
+        "sshKeys": null,
+        "bus" : "VIRTIO",
+        "licenceType" : "LINUX",
+        "cpuHotPlug" : true,
+        "cpuHotUnplug" : false,
+        "ramHotPlug" : true,
+        "ramHotUnplug" : false,
+        "nicHotPlug" : true,
+        "nicHotUnplug" : true,
+        "discVirtioHotPlug" : true,
+        "discVirtioHotUnplug" : true,
+        "discScsiHotPlug" : false,
+        "discScsiHotUnplug" : false,
+        "deviceNumber" : 3
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 8b2b1f5..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/attach_volume.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/create_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/create_node.json b/libcloud/test/compute/fixtures/profitbricks/create_node.json
new file mode 100644
index 0000000..b732980
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/create_node.json
@@ -0,0 +1,37 @@
+{
+    "id": "srv-2",
+    "type": "server",
+    "href": "cloudapi/v3/datacenters/f3f7ca3c-6f3d-4a4d-b3d6-15853ae5ba78/servers/srv-2",
+    "metadata": {
+        "createdDate": "2016-10-19T13:25:19Z",
+        "createdBy": "test@test.te",
+        "etag": "9bea2412ac556b402a07260fc0d1603f",
+        "lastModifiedDate": "2016-10-19T13:25:19Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Test",
+        "cores": 1,
+        "ram": 512,
+        "availabilityZone": "ZONE_1",
+        "vmState": null,
+        "bootCdrom": null,
+        "bootVolume": null,
+        "cpuFamily": "INTEL_XEON"
+    },
+    "entities": {
+        "volumes": {
+            "id": "srv-2/volumes",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/f3f7ca3c-6f3d-4a4d-b3d6-15853ae5ba78/servers/srv-2/volumes",
+            "items": [
+                {
+                    "id": "53abb4de-b37b-4025-b139-3e09141e20bb",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/srv-2/volumes/53abb4de-b37b-4025-b139-3e09141e20bb"
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index ad515ba..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/create_node.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/create_volume.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/create_volume.json b/libcloud/test/compute/fixtures/profitbricks/create_volume.json
new file mode 100644
index 0000000..59720d9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/create_volume.json
@@ -0,0 +1,35 @@
+{
+    "id" : "vol-2",
+    "type" : "volume",
+    "href" : "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+    "metadata" : {
+        "createdDate" : "2016-10-17T13:13:36Z",
+        "createdBy" : "test@test.te",
+        "etag" : "c1800ce349033f9cd2c095ea1ea4976a",
+        "lastModifiedDate" : "2016-10-17T13:47:52Z",
+        "lastModifiedBy" : "test@test.te",
+        "state" : "BUSY"
+    },
+    "properties" : {
+        "name": "Updated storage name",
+        "type": "HDD",
+        "size": 40,
+        "availabilityZone": "AUTO",
+        "image": "bvol-img",
+        "imagePassword": null,
+        "sshKeys": null,
+        "bus": "VIRTIO",
+        "licenceType": "LINUX",
+        "cpuHotPlug": true,
+        "cpuHotUnplug": false,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "deviceNumber": 3
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 326879a..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/create_volume.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/create_volume_snapshot.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/create_volume_snapshot.json b/libcloud/test/compute/fixtures/profitbricks/create_volume_snapshot.json
new file mode 100644
index 0000000..a90f585
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/create_volume_snapshot.json
@@ -0,0 +1,30 @@
+{
+    "id": "sshot",
+    "type": "snapshot",
+    "href": "/cloudapi/v3/snapshots/sshot",
+    "metadata": {
+        "createdDate": "2016-10-26T11:38:45Z",
+        "createdBy": "test@test.te",
+        "etag": "01873262ac042b5f44ed33b4241225b4",
+        "lastModifiedDate": "2016-10-26T11:38:45Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Test Created Snapshot",
+        "description": "Test Created Snapshot",
+        "location": "us/las",
+        "size": 10,
+        "cpuHotPlug": true,
+        "cpuHotUnplug": false,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "licenceType": "LINUX"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 1dacfaf..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/destroy_node.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index 0591e1c..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/destroy_volume.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index fafc327..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/detach_volume.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index 5259d45..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_clear_datacenter.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.json
new file mode 100644
index 0000000..3f42689
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.json
@@ -0,0 +1,20 @@
+{
+    "id": "dc-1",
+    "type": "datacenter",
+    "href": "/cloudapi/v3/datacenters/dc-1",
+    "metadata": {
+        "createdDate": "2016-10-18T17:20:56Z",
+        "createdBy": "test@test.te",
+        "etag": "c2d3d4d9bbdc0fff7d3c5c3864a68a46",
+        "lastModifiedDate": "2016-10-18T17:20:56Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Test Data Center",
+        "description": "Test Data Center.",
+        "location": "us/las",
+        "version": null,
+        "features": []
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index f4238d8..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_create_datacenter.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_firewall_rule.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_firewall_rule.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_firewall_rule.json
new file mode 100644
index 0000000..a5f4210
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_firewall_rule.json
@@ -0,0 +1,24 @@
+{
+    "id": "fwr-1",
+    "type": "firewall-rule",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/fwr-1",
+    "metadata": {
+        "createdDate": "2016-10-19T11:08:04Z",
+        "createdBy": "test@test.te",
+        "etag": "2a21551ba4adf85d9fb04b05a6938bcc",
+        "lastModifiedDate": "2016-10-19T11:08:04Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Test created firewall rule",
+        "protocol": "TCP",
+        "sourceMac": null,
+        "sourceIp": null,
+        "targetIp": null,
+        "icmpCode": null,
+        "icmpType": null,
+        "portRangeStart": 80,
+        "portRangeEnd": 80
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_ip_block.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_ip_block.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_ip_block.json
new file mode 100644
index 0000000..56b0544
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_ip_block.json
@@ -0,0 +1,22 @@
+{
+    "id": "ipb-1",
+    "type": "ipblock",
+    "href": "/cloudapi/v3/ipblocks/ipb-1",
+    "metadata": {
+        "createdDate": "2016-10-26T15:05:36Z",
+        "createdBy": "test@test.te",
+        "etag": "acbf00bacf7ee48d4b8bc4e7413e1f30",
+        "lastModifiedDate": "2016-10-26T15:05:36Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "ips": [
+            "11.12.13.14",
+            "15.16.17.18"
+        ],
+        "location": "de/fkb",
+        "size": 2,
+        "name": "Test Created IP Block"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_lan.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_lan.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_lan.json
new file mode 100644
index 0000000..0e2b9cc
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_lan.json
@@ -0,0 +1,17 @@
+{
+    "id" : "10",
+    "type" : "lan",
+    "href" : "/cloudapi/v3/datacenters/dc-1/lans/10",
+    "metadata" : {
+        "createdDate": "2016-10-17T11:33:11Z",
+        "createdBy": "test@test.te",
+        "etag": "53b215b8ec0356a649955dab019845a4",
+        "lastModifiedDate": "2016-10-18T15:13:44Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties" : {
+        "name" : "Test Created Lan",
+        "public" : true
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_load_balancer.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_load_balancer.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_load_balancer.json
new file mode 100644
index 0000000..67af86b
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_load_balancer.json
@@ -0,0 +1,18 @@
+{
+    "id": "bal-1",
+    "type": "loadbalancer",
+    "href": "/cloudapi/v3/datacenters/dc-1/loadbalancers/bal-1",
+    "metadata": {
+        "createdDate": "2016-10-26T13:02:33Z",
+        "createdBy": "test@test.te",
+        "etag": "71e8df57a58615b9e15400ede4138b41",
+        "lastModifiedDate": "2016-10-26T13:02:33Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Test load balancer",
+        "ip": null,
+        "dhcp": true
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.json b/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.json
new file mode 100644
index 0000000..5e45994
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.json
@@ -0,0 +1,22 @@
+{
+    "id": "nic-2",
+    "type": "nic",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics/nic-2",
+    "metadata": {
+        "createdDate": "2016-10-19T08:18:50Z",
+        "createdBy": "test@test.te",
+        "etag": "8679142b0b1b70c8b8c09a8b31e6ded9",
+        "lastModifiedDate": "2016-10-19T08:18:50Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Creating a test network interface.",
+        "mac": null,
+        "ips": [],
+        "dhcp": true,
+        "lan": 1,
+        "firewallActive": null,
+        "nat": null
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 830d41d..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_create_network_interface.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.json
new file mode 100644
index 0000000..4f20e63
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.json
@@ -0,0 +1,401 @@
+{
+    "id": "dc-1",
+    "type": "datacenter",
+    "href": "/cloudapi/v3/datacenters/dc-1",
+    "metadata": {
+        "createdDate": "2016-10-17T11:33:11Z",
+        "createdBy": "test@test.test",
+        "etag": "53b215b8ec0356a649955dab019845a4",
+        "lastModifiedDate": "2016-10-18T15:13:44Z",
+        "lastModifiedBy": "test@test.test",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Test Data Center",
+        "description": "This is a test data center.",
+        "location": "de/fkb",
+        "version": 35,
+        "features": [
+            "SSD",
+            "MULTIPLE_CPU"
+        ]
+    },
+    "entities": {
+        "servers": {
+            "id": "dc-1/servers",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers",
+            "items": [
+                {
+                    "id": "srv-1",
+                    "type": "server",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1",
+                    "metadata": {
+                        "createdDate": "2016-10-18T07:28:05Z",
+                        "createdBy": "test@test.test",
+                        "etag": "53b215b8ec0356a649955dab019845a4",
+                        "lastModifiedDate": "2016-10-18T15:13:44Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Made with a stray volume and included size.",
+                        "cores": 2,
+                        "ram": 4096,
+                        "availabilityZone": "AUTO",
+                        "vmState": "RUNNING",
+                        "bootCdrom": null,
+                        "bootVolume": {
+                            "id": "bvol-1",
+                            "type": "volume",
+                            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+                            "metadata": {
+                                "createdDate": "2016-10-18T07:20:41Z",
+                                "createdBy": "test@test.test",
+                                "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                                "lastModifiedDate": "2016-10-18T07:20:41Z",
+                                "lastModifiedBy": "test@test.test",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Bootable and linkable",
+                                "type": "HDD",
+                                "size": 10,
+                                "image": "bvol-img",
+                                "imagePassword": null,
+                                "bus": "VIRTIO",
+                                "licenceType": "LINUX",
+                                "cpuHotPlug": true,
+                                "cpuHotUnplug": false,
+                                "ramHotPlug": true,
+                                "ramHotUnplug": false,
+                                "nicHotPlug": true,
+                                "nicHotUnplug": true,
+                                "discVirtioHotPlug": true,
+                                "discVirtioHotUnplug": true,
+                                "discScsiHotPlug": false,
+                                "discScsiHotUnplug": false,
+                                "deviceNumber": 1
+                            }
+                        },
+                        "cpuFamily": "AMD_OPTERON"
+                    },
+                    "entities": {
+                        "cdroms": {
+                            "id": "srv-1/cdroms",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/cdroms",
+                            "items": []
+                        },
+                        "volumes": {
+                            "id": "srv-1/volumes",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes",
+                            "items": [
+                                {
+                                    "id": "d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+                                    "type": "volume",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/d6688ced-700d-4c9c-a3a7-9f7170c5edc3"
+                                },
+                                {
+                                    "id": "vol-2",
+                                    "type": "volume",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/vol-2"
+                                },
+                                {
+                                    "id": "bvol-1",
+                                    "type": "volume",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1"
+                                }
+                            ]
+                        },
+                        "nics": {
+                            "id": "srv-1/nics",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics",
+                            "items": []
+                        }
+                    }
+                },
+                {
+                    "id": "s-3",
+                    "type": "server",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3",
+                    "metadata": {
+                        "createdDate": "2016-10-17T11:33:20Z",
+                        "createdBy": "test@test.test",
+                        "etag": "f6c94daafaf8ef852e2dc4b82a903c7b",
+                        "lastModifiedDate": "2016-10-17T16:13:43Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Updated this node",
+                        "cores": 3,
+                        "ram": 3072,
+                        "availabilityZone": "AUTO",
+                        "vmState": "RUNNING",
+                        "bootCdrom": null,
+                        "bootVolume": {
+                            "id": "21d7e7de-5054-4041-b691-717aa8b3c799",
+                            "type": "volume",
+                            "href": "/cloudapi/v3/datacenters/dc-1/volumes/21d7e7de-5054-4041-b691-717aa8b3c799",
+                            "metadata": {
+                                "createdDate": "2016-10-17T11:33:20Z",
+                                "createdBy": "test@test.test",
+                                "etag": "a9d0b923527efae5e7071e9118e9eece",
+                                "lastModifiedDate": "2016-10-17T11:33:20Z",
+                                "lastModifiedBy": "test@test.test",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Image and location and size. - volume",
+                                "type": "HDD",
+                                "size": 50,
+                                "image": "bvol-img",
+                                "imagePassword": null,
+                                "bus": "VIRTIO",
+                                "licenceType": "LINUX",
+                                "cpuHotPlug": true,
+                                "cpuHotUnplug": false,
+                                "ramHotPlug": true,
+                                "ramHotUnplug": false,
+                                "nicHotPlug": true,
+                                "nicHotUnplug": true,
+                                "discVirtioHotPlug": true,
+                                "discVirtioHotUnplug": true,
+                                "discScsiHotPlug": false,
+                                "discScsiHotUnplug": false,
+                                "deviceNumber": 1
+                            }
+                        },
+                        "cpuFamily": "INTEL_XEON"
+                    },
+                    "entities": {
+                        "cdroms": {
+                            "id": "s-3/cdroms",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/cdroms",
+                            "items": []
+                        },
+                        "volumes": {
+                            "id": "s-3/volumes",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/volumes",
+                            "items": [
+                                {
+                                    "id": "21d7e7de-5054-4041-b691-717aa8b3c799",
+                                    "type": "volume",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/21d7e7de-5054-4041-b691-717aa8b3c799"
+                                }
+                            ]
+                        },
+                        "nics": {
+                            "id": "s-3/nics",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics",
+                            "items": [
+                                {
+                                    "id": "nic-1",
+                                    "type": "nic",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1"
+                                }
+                            ]
+                        }
+                    }
+                }
+            ]
+        },
+        "volumes": {
+            "id": "dc-1/volumes",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes",
+            "items": [
+                {
+                    "id": "vol-2",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+                    "metadata": {
+                        "createdDate": "2016-10-18T15:13:44Z",
+                        "createdBy": "test@test.test",
+                        "etag": "a96f7781920c2890c25f967e66e6ee91",
+                        "lastModifiedDate": "2016-10-18T15:13:44Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Unnamed HDD Storage",
+                        "type": "HDD",
+                        "size": 10,
+                        "availabilityZone": "AUTO",
+                        "image": null,
+                        "imagePassword": null,
+                        "sshKeys": null,
+                        "bus": "VIRTIO",
+                        "licenceType": null,
+                        "cpuHotPlug": false,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": false,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": false,
+                        "nicHotUnplug": false,
+                        "discVirtioHotPlug": false,
+                        "discVirtioHotUnplug": false,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 2
+                    }
+                },
+                {
+                    "id": "bvol-1",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+                    "metadata": {
+                        "createdDate": "2016-10-18T07:20:41Z",
+                        "createdBy": "test@test.test",
+                        "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                        "lastModifiedDate": "2016-10-18T07:20:41Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Bootable and linkable",
+                        "type": "HDD",
+                        "size": 10,
+                        "availabilityZone": "AUTO",
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "sshKeys": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 1
+                    }
+                },
+                {
+                    "id": "d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+                    "metadata": {
+                        "createdDate": "2016-10-17T13:13:36Z",
+                        "createdBy": "test@test.test",
+                        "etag": "c1800ce349033f9cd2c095ea1ea4976a",
+                        "lastModifiedDate": "2016-10-17T13:47:52Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Updated storage name",
+                        "type": "HDD",
+                        "size": 40,
+                        "availabilityZone": "AUTO",
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "sshKeys": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 3
+                    }
+                },
+                {
+                    "id": "21d7e7de-5054-4041-b691-717aa8b3c799",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/21d7e7de-5054-4041-b691-717aa8b3c799",
+                    "metadata": {
+                        "createdDate": "2016-10-17T11:33:20Z",
+                        "createdBy": "test@test.test",
+                        "etag": "a9d0b923527efae5e7071e9118e9eece",
+                        "lastModifiedDate": "2016-10-17T11:33:20Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Image and location and size. - volume",
+                        "type": "HDD",
+                        "size": 50,
+                        "availabilityZone": "AUTO",
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "sshKeys": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 1
+                    }
+                }
+            ]
+        },
+        "loadbalancers": {
+            "id": "dc-1/loadbalancers",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/loadbalancers",
+            "items": []
+        },
+        "lans": {
+            "id": "dc-1/lans",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/lans",
+            "items": [
+                {
+                    "id": "2",
+                    "type": "lan",
+                    "href": "/cloudapi/v3/datacenters/dc-1/lans/2",
+                    "metadata": {
+                        "createdDate": "2016-10-17T18:19:43Z",
+                        "createdBy": "test@test.test",
+                        "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                        "lastModifiedDate": "2016-10-18T07:20:41Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Switch for LAN 2",
+                        "public": false
+                    },
+                    "entities": {
+                        "nics": {
+                            "id": "2/nics",
+                            "type": "collection",
+                            "href": "/cloudapi/v3/datacenters/dc-1/lans/2/nics",
+                            "items": [
+                                {
+                                    "id": "nic-1",
+                                    "type": "nic",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1"
+                                }
+                            ]
+                        }
+                    }
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index cb4a1a0..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_describe_datacenter.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_firewall_rule.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_firewall_rule.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_firewall_rule.json
new file mode 100644
index 0000000..523245d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_firewall_rule.json
@@ -0,0 +1,24 @@
+{
+    "id": "fw2",
+    "type": "firewall-rule",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/fw2",
+    "metadata": {
+        "createdDate": "2016-10-19T09:55:10Z",
+        "createdBy": "test@test.te",
+        "etag": "00bb5b86562db1ed19ca38697e485160",
+        "lastModifiedDate": "2016-10-19T09:55:10Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "HTTPs (SSL)",
+        "protocol": "TCP",
+        "sourceMac": null,
+        "sourceIp": null,
+        "targetIp": null,
+        "icmpCode": null,
+        "icmpType": null,
+        "portRangeStart": 443,
+        "portRangeEnd": 443
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_image.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_image.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_image.json
new file mode 100644
index 0000000..a6977ac
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_image.json
@@ -0,0 +1,32 @@
+{
+    "id": "img-2",
+    "type": "image",
+    "href": "/cloudapi/v3/images/img-2",
+    "metadata": {
+        "createdDate": "2015-10-09T12:06:34Z",
+        "createdBy": "test@test.te",
+        "etag": "bbf76112358af2fc5dd1bf21de8988db",
+        "lastModifiedDate": "2015-11-11T15:23:20Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "vivid-server-cloudimg-amd64-disk1.img",
+        "description": null,
+        "location": "de/fkb",
+        "size": 2,
+        "cpuHotPlug": false,
+        "cpuHotUnplug": false,
+        "ramHotPlug": false,
+        "ramHotUnplug": false,
+        "nicHotPlug": false,
+        "nicHotUnplug": false,
+        "discVirtioHotPlug": false,
+        "discVirtioHotUnplug": false,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "licenceType": "UNKNOWN",
+        "imageType": "HDD",
+        "public": false
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_ip_block.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_ip_block.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_ip_block.json
new file mode 100644
index 0000000..63f59e5
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_ip_block.json
@@ -0,0 +1,21 @@
+{
+    "id": "ipb-2",
+    "type": "ipblock",
+    "href": "/cloudapi/v3/ipblocks/ipb-2",
+    "metadata": {
+        "createdDate": "2016-10-26T15:05:12Z",
+        "createdBy": "test@test.te",
+        "etag": "43e05b766899950bc8a5aeee0fd89b05",
+        "lastModifiedDate": "2016-10-26T15:05:12Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "ips": [
+            "78.137.101.250"
+        ],
+        "location": "de/fkb",
+        "size": 1,
+        "name": "Test IP Block One"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_lan.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_lan.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_lan.json
new file mode 100644
index 0000000..459a74e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_lan.json
@@ -0,0 +1,24 @@
+{
+    "id" : "10",
+    "type" : "lan",
+    "href" : "/cloudapi/v3/datacenters/dc-1/lans/10",
+    "metadata" : {
+        "createdDate": "2016-10-17T11:33:11Z",
+        "createdBy": "test@test.te",
+        "etag": "53b215b8ec0356a649955dab019845a4",
+        "lastModifiedDate": "2016-10-18T15:13:44Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties" : {
+        "name" : "Test Created Lan",
+        "public" : true
+    },
+    "entities": {
+        "nics": {
+            "id": "10/nics",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/lans/10/nics"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_load_balancer.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_load_balancer.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_load_balancer.json
new file mode 100644
index 0000000..bb26434
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_load_balancer.json
@@ -0,0 +1,25 @@
+{
+    "id": "bal-1",
+    "type": "loadbalancer",
+    "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/bal-1",
+    "metadata": {
+        "createdDate": "2016-10-26T13:02:33Z",
+        "createdBy": "test@test.te",
+        "etag": "71e8df57a58615b9e15400ede4138b41",
+        "lastModifiedDate": "2016-10-26T13:02:33Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Test One",
+        "ip": "111.112.113.114",
+        "dhcp": true
+    },
+    "entities": {
+        "balancednics": {
+            "id": "bal-1/balancednics",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/bal-1/balancednics"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_location.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_location.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_location.json
new file mode 100644
index 0000000..6cd6628
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_location.json
@@ -0,0 +1,12 @@
+{
+    "id": "de/fkb",
+    "type": "location",
+    "href": "/cloudapi/v3/locations/de/fkb",
+    "properties": {
+        "name": "karlsruhe",
+        "features": [
+            "SSD",
+            "MULTIPLE_CPU"
+        ]
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.json
new file mode 100644
index 0000000..dedecce
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.json
@@ -0,0 +1,31 @@
+{
+    "id": "nic-2",
+    "type": "nic",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2",
+    "metadata": {
+        "createdDate": "2016-10-17T15:46:38Z",
+        "createdBy": "test@test.te",
+        "etag": "dbd8216137cf0ec9951170f93fa8fa53",
+        "lastModifiedDate": "2016-10-17T18:19:43Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Updated from LibCloud",
+        "mac": "02:01:0b:9d:4d:ce",
+        "ips": [
+            "10.15.124.11"
+        ],
+        "dhcp": false,
+        "lan": 2,
+        "firewallActive": true,
+        "nat": false
+    },
+    "entities": {
+        "firewallrules": {
+            "id": "nic-1/firewallrules",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index e2235b9..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_describe_network_interface.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.json
new file mode 100644
index 0000000..476a4b9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.json
@@ -0,0 +1,111 @@
+{
+    "id": "srv-1",
+    "type": "server",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1",
+    "metadata": {
+        "createdDate": "2016-10-18T07:28:05Z",
+        "createdBy": "test@test.test",
+        "etag": "e7cf186125f51f3d9511754a40dcd12c",
+        "lastModifiedDate": "2016-10-18T07:28:05Z",
+        "lastModifiedBy": "test@test.test",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "A test node",
+        "cores": 2,
+        "ram": 4096,
+        "availabilityZone": "AUTO",
+        "vmState": "RUNNING",
+        "bootCdrom": null,
+        "bootVolume": {
+            "id": "bvol-1",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+            "metadata": {
+                "createdDate": "2016-10-18T07:20:41Z",
+                "createdBy": "test@test.test",
+                "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                "lastModifiedDate": "2016-10-18T07:20:41Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "A test node boot volume",
+                "type": "HDD",
+                "size": 10,
+                "image": "bvol-img",
+                "imagePassword": null,
+                "bus": "VIRTIO",
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 1
+            }
+        },
+        "cpuFamily": "AMD_OPTERON"
+    },
+    "entities": {
+        "cdroms": {
+            "id": "srv-1/cdroms",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/cdroms",
+            "items": []
+        },
+        "volumes": {
+            "id": "srv-1/volumes",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes",
+            "items": [
+                {
+                    "id": "bvol-1",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+                    "metadata": {
+                        "createdDate": "2016-10-18T07:20:41Z",
+                        "createdBy": "test@test.test",
+                        "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                        "lastModifiedDate": "2016-10-18T07:20:41Z",
+                        "lastModifiedBy": "test@test.test",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "A test node volume",
+                        "type": "HDD",
+                        "size": 10,
+                        "availabilityZone": "AUTO",
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "sshKeys": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 1
+                    }
+                }
+            ]
+        },
+        "nics": {
+            "id": "srv-1/nics",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics",
+            "items": []
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 5567e8f..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_describe_node.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_snapshot.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_snapshot.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_snapshot.json
new file mode 100644
index 0000000..06cce65
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_snapshot.json
@@ -0,0 +1,30 @@
+{
+    "id": "sshot",
+    "type": "snapshot",
+    "href": "/cloudapi/v3/snapshots/sshot",
+    "metadata": {
+        "createdDate": "2016-10-26T11:38:45Z",
+        "createdBy": "test@test.te",
+        "etag": "01873262ac042b5f44ed33b4241225b4",
+        "lastModifiedDate": "2016-10-26T11:38:45Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Test Snapshot",
+        "description": "Test Snapshot",
+        "location": "us/las",
+        "size": 10,
+        "cpuHotPlug": true,
+        "cpuHotUnplug": false,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "licenceType": "LINUX"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.json b/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.json
new file mode 100644
index 0000000..d0eab6a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.json
@@ -0,0 +1,35 @@
+{
+    "id": "vol-2",
+    "type": "volume",
+    "href": "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+    "metadata": {
+        "createdDate": "2016-10-17T13:13:36Z",
+        "createdBy": "test@test.te",
+        "etag": "c1800ce349033f9cd2c095ea1ea4976a",
+        "lastModifiedDate": "2016-10-17T13:47:52Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Updated storage name",
+        "type": "HDD",
+        "size": 40,
+        "availabilityZone": "AUTO",
+        "image": "bvol-img",
+        "imagePassword": null,
+        "sshKeys": null,
+        "bus": "VIRTIO",
+        "licenceType": "LINUX",
+        "cpuHotPlug": true,
+        "cpuHotUnplug": false,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "deviceNumber": 3
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 050b4b5..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_describe_volume.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index 4d36bdb..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_destroy_datacenter.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index 6584f06..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_destroy_network_interface.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_attached_volumes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_attached_volumes.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_attached_volumes.json
new file mode 100644
index 0000000..6777ba3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_attached_volumes.json
@@ -0,0 +1,112 @@
+{
+    "id": "srv-1/volumes",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes",
+    "items": [
+        {
+            "id": "d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+            "metadata": {
+                "createdDate": "2016-10-17T13:13:36Z",
+                "createdBy": "test@test.test",
+                "etag": "c1800ce349033f9cd2c095ea1ea4976a",
+                "lastModifiedDate": "2016-10-17T13:47:52Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Volume one",
+                "type": "HDD",
+                "size": 40,
+                "availabilityZone": "AUTO",
+                "image": "bvol-img",
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": "VIRTIO",
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 3
+            }
+        },
+        {
+            "id": "vol-2",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+            "metadata": {
+                "createdDate": "2016-10-18T15:13:44Z",
+                "createdBy": "test@test.test",
+                "etag": "a96f7781920c2890c25f967e66e6ee91",
+                "lastModifiedDate": "2016-10-18T15:13:44Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Volume two",
+                "type": "HDD",
+                "size": 10,
+                "availabilityZone": "AUTO",
+                "image": null,
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": "VIRTIO",
+                "licenceType": null,
+                "cpuHotPlug": false,
+                "cpuHotUnplug": false,
+                "ramHotPlug": false,
+                "ramHotUnplug": false,
+                "nicHotPlug": false,
+                "nicHotUnplug": false,
+                "discVirtioHotPlug": false,
+                "discVirtioHotUnplug": false,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 2
+            }
+        },
+        {
+            "id": "bvol-1",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+            "metadata": {
+                "createdDate": "2016-10-18T07:20:41Z",
+                "createdBy": "test@test.test",
+                "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                "lastModifiedDate": "2016-10-18T07:20:41Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Volume three",
+                "type": "HDD",
+                "size": 10,
+                "availabilityZone": "AUTO",
+                "image": "bvol-img",
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": "VIRTIO",
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 1
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.json
new file mode 100644
index 0000000..912c0fc
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.json
@@ -0,0 +1,52 @@
+{
+    "id": "datacenters",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/",
+    "items": [
+        {
+            "id": "dc-1",
+            "type": "datacenter",
+            "href": "/cloudapi/v3/datacenters/dc-1",
+            "metadata": {
+                "createdDate": "2016-10-14T07:24:59Z",
+                "createdBy": "test@test.test",
+                "etag": "bdddec2287cb7723e86ac088bf644606",
+                "lastModifiedDate": "2016-10-17T15:27:25Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test One.",
+                "description": "A test data center",
+                "location": "de/fra",
+                "version": 3,
+                "features": [
+                    "SSD",
+                    "MULTIPLE_CPU"
+                ]
+            },
+            "entities": {
+                "servers": {
+                    "id": "983a45be-a9aa-427a-8117-271ce9f392bb/servers",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers"
+                },
+                "volumes": {
+                    "id": "983a45be-a9aa-427a-8117-271ce9f392bb/volumes",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes"
+                },
+                "loadbalancers": {
+                    "id": "983a45be-a9aa-427a-8117-271ce9f392bb/loadbalancers",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/loadbalancers"
+                },
+                "lans": {
+                    "id": "983a45be-a9aa-427a-8117-271ce9f392bb/lans",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/lans"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index dfb9245..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_list_datacenters.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_firewall_rules.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_firewall_rules.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_firewall_rules.json
new file mode 100644
index 0000000..7128877
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_firewall_rules.json
@@ -0,0 +1,79 @@
+{
+    "id": "nic-2/firewallrules",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules",
+    "items": [
+        {
+            "id": "fwr-1",
+            "type": "firewall-rule",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/fwr-1",
+            "metadata": {
+                "createdDate": "2016-10-19T11:08:10Z",
+                "createdBy": "test@test.te",
+                "etag": "b91a2e082a7422dafb79d84a07fb2a28",
+                "lastModifiedDate": "2016-10-19T11:19:04Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test updated firewall rule",
+                "protocol": "TCP",
+                "sourceMac": null,
+                "sourceIp": null,
+                "targetIp": null,
+                "icmpCode": null,
+                "icmpType": null,
+                "portRangeStart": 80,
+                "portRangeEnd": 80
+            }
+        },
+        {
+            "id": "fw2",
+            "type": "firewall-rule",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/fw2",
+            "metadata": {
+                "createdDate": "2016-10-19T09:55:10Z",
+                "createdBy": "test@test.te",
+                "etag": "00bb5b86562db1ed19ca38697e485160",
+                "lastModifiedDate": "2016-10-19T09:55:10Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "HTTPs (SSL)",
+                "protocol": "TCP",
+                "sourceMac": null,
+                "sourceIp": null,
+                "targetIp": null,
+                "icmpCode": null,
+                "icmpType": null,
+                "portRangeStart": 443,
+                "portRangeEnd": 443
+            }
+        },
+        {
+            "id": "6238b1e2-c706-4dc9-80a9-307fa0bd4287",
+            "type": "firewall-rule",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/6238b1e2-c706-4dc9-80a9-307fa0bd4287",
+            "metadata": {
+                "createdDate": "2016-10-19T09:55:10Z",
+                "createdBy": "test@test.te",
+                "etag": "00bb5b86562db1ed19ca38697e485160",
+                "lastModifiedDate": "2016-10-19T09:55:10Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "HTTP Webserver",
+                "protocol": "TCP",
+                "sourceMac": null,
+                "sourceIp": null,
+                "targetIp": null,
+                "icmpCode": null,
+                "icmpType": null,
+                "portRangeStart": 80,
+                "portRangeEnd": 80
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_ip_blocks.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_ip_blocks.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_ip_blocks.json
new file mode 100644
index 0000000..df3c9cb
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_ip_blocks.json
@@ -0,0 +1,50 @@
+{
+    "id": "ipblocks",
+    "type": "collection",
+    "href": "/cloudapi/v3/ipblocks",
+    "items": [
+        {
+            "id": "ipb-1",
+            "type": "ipblock",
+            "href": "/cloudapi/v3/ipblocks/ipb-1",
+            "metadata": {
+                "createdDate": "2016-10-26T15:05:36Z",
+                "createdBy": "test@test.te",
+                "etag": "acbf00bacf7ee48d4b8bc4e7413e1f30",
+                "lastModifiedDate": "2016-10-26T15:05:36Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "ips": [
+                    "78.137.101.252",
+                    "78.137.101.251"
+                ],
+                "location": "de/fkb",
+                "size": 2,
+                "name": "Test IP Block One"
+            }
+        },
+        {
+            "id": "ipb-2",
+            "type": "ipblock",
+            "href": "/cloudapi/v3/ipblocks/ipb-2",
+            "metadata": {
+                "createdDate": "2016-10-26T15:05:12Z",
+                "createdBy": "test@test.te",
+                "etag": "43e05b766899950bc8a5aeee0fd89b05",
+                "lastModifiedDate": "2016-10-26T15:05:12Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "ips": [
+                    "78.137.101.250"
+                ],
+                "location": "de/fkb",
+                "size": 1,
+                "name": "Test IP Block One"
+            }
+        }
+    ]
+}
\ No newline at end of file


[6/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Posted by an...@apache.org.
[LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Refactoring the compute  driver to remove support for the EOL SOAP api and modifying api calls to use the REST api (v3).

Removing XML test fixtures and replacing them with JSON fixtures.

Providing wrappers for all new functionality provided in v3 of the Cloud API.

Addressing an issue in libcloud/common/base.py where a http status code of 202 would not be flagged as a successful request.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/2569a5f2
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/2569a5f2
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/2569a5f2

Branch: refs/heads/trunk
Commit: 2569a5f2a953314483712667a964e5463990f617
Parents: 3b515f4
Author: Matt Finucane <ma...@gmail.com>
Authored: Mon Oct 10 13:17:10 2016 +0200
Committer: Matt Finucane <ma...@gmail.com>
Committed: Thu Nov 3 23:44:32 2016 +0100

----------------------------------------------------------------------
 libcloud/common/base.py                         |    2 +-
 libcloud/compute/drivers/profitbricks.py        | 4101 ++++++++++---
 .../fixtures/profitbricks/attach_volume.json    |   34 +
 .../fixtures/profitbricks/attach_volume.xml     |   12 -
 .../fixtures/profitbricks/create_node.json      |   37 +
 .../fixtures/profitbricks/create_node.xml       |   13 -
 .../fixtures/profitbricks/create_volume.json    |   35 +
 .../fixtures/profitbricks/create_volume.xml     |   13 -
 .../profitbricks/create_volume_snapshot.json    |   30 +
 .../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.json      |   20 +
 .../profitbricks/ex_create_datacenter.xml       |   13 -
 .../profitbricks/ex_create_firewall_rule.json   |   24 +
 .../profitbricks/ex_create_ip_block.json        |   22 +
 .../fixtures/profitbricks/ex_create_lan.json    |   17 +
 .../profitbricks/ex_create_load_balancer.json   |   18 +
 .../ex_create_network_interface.json            |   22 +
 .../ex_create_network_interface.xml             |   13 -
 .../profitbricks/ex_describe_datacenter.json    |  401 ++
 .../profitbricks/ex_describe_datacenter.xml     |   15 -
 .../profitbricks/ex_describe_firewall_rule.json |   24 +
 .../profitbricks/ex_describe_image.json         |   32 +
 .../profitbricks/ex_describe_ip_block.json      |   21 +
 .../fixtures/profitbricks/ex_describe_lan.json  |   24 +
 .../profitbricks/ex_describe_load_balancer.json |   25 +
 .../profitbricks/ex_describe_location.json      |   12 +
 .../ex_describe_network_interface.json          |   31 +
 .../ex_describe_network_interface.xml           |   26 -
 .../fixtures/profitbricks/ex_describe_node.json |  111 +
 .../fixtures/profitbricks/ex_describe_node.xml  |   77 -
 .../profitbricks/ex_describe_snapshot.json      |   30 +
 .../profitbricks/ex_describe_volume.json        |   35 +
 .../profitbricks/ex_describe_volume.xml         |   22 -
 .../profitbricks/ex_destroy_datacenter.xml      |   10 -
 .../ex_destroy_network_interface.xml            |   12 -
 .../profitbricks/ex_list_attached_volumes.json  |  112 +
 .../profitbricks/ex_list_datacenters.json       |   52 +
 .../profitbricks/ex_list_datacenters.xml        |   19 -
 .../profitbricks/ex_list_firewall_rules.json    |   79 +
 .../profitbricks/ex_list_ip_blocks.json         |   50 +
 .../fixtures/profitbricks/ex_list_lans.json     |  157 +
 .../ex_list_load_balanced_nics.json             |   69 +
 .../profitbricks/ex_list_load_balancers.json    |  216 +
 .../ex_list_network_interfaces.json             |   69 +
 .../profitbricks/ex_list_network_interfaces.xml |   75 -
 .../profitbricks/ex_rename_datacenter.json      |   46 +
 .../profitbricks/ex_set_inet_access.json        |   31 +
 .../fixtures/profitbricks/ex_start_node.xml     |   10 -
 .../fixtures/profitbricks/ex_stop_node.xml      |   10 -
 .../profitbricks/ex_update_datacenter.xml       |   12 -
 .../profitbricks/ex_update_firewall_rule.json   |   25 +
 .../fixtures/profitbricks/ex_update_image.json  |   32 +
 .../fixtures/profitbricks/ex_update_lan.json    |   24 +
 .../profitbricks/ex_update_load_balancer.json   |   18 +
 .../ex_update_network_interface.json            |   31 +
 .../ex_update_network_interface.xml             |   12 -
 .../fixtures/profitbricks/ex_update_node.json   |   45 +
 .../fixtures/profitbricks/ex_update_node.xml    |   12 -
 .../profitbricks/ex_update_snapshot.json        |   30 +
 .../fixtures/profitbricks/ex_update_volume.json |   35 +
 .../fixtures/profitbricks/ex_update_volume.xml  |   12 -
 .../fixtures/profitbricks/list_images.json      |  199 +
 .../fixtures/profitbricks/list_images.xml       |   43 -
 .../fixtures/profitbricks/list_locations.json   |   43 +
 .../fixtures/profitbricks/list_nodes.json       |  169 +
 .../fixtures/profitbricks/list_nodes.xml        |  172 -
 .../fixtures/profitbricks/list_snapshots.json   |   37 +
 .../fixtures/profitbricks/list_volumes.json     |  112 +
 .../fixtures/profitbricks/list_volumes.xml      |   66 -
 .../fixtures/profitbricks/reboot_node.xml       |   10 -
 libcloud/test/compute/test_profitbricks.py      | 5377 ++++++++++++++++--
 74 files changed, 10999 insertions(+), 1894 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/common/base.py
----------------------------------------------------------------------
diff --git a/libcloud/common/base.py b/libcloud/common/base.py
index 3b03fa3..cfe075a 100644
--- a/libcloud/common/base.py
+++ b/libcloud/common/base.py
@@ -212,7 +212,7 @@ class Response(object):
         :rtype: ``bool``
         :return: ``True`` or ``False``
         """
-        return self.status in [httplib.OK, httplib.CREATED]
+        return self.status in [httplib.OK, httplib.CREATED, httplib.ACCEPTED]
 
     def _decompress_response(self, body, headers):
         """


[5/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/compute/drivers/profitbricks.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/profitbricks.py b/libcloud/compute/drivers/profitbricks.py
index ab217f0..8013e3b 100644
--- a/libcloud/compute/drivers/profitbricks.py
+++ b/libcloud/compute/drivers/profitbricks.py
@@ -16,23 +16,22 @@
 """
 import base64
 
+import json
 import copy
 import time
+import urllib
 
-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.common.base import ConnectionUserAndKey, JsonResponse
 from libcloud.compute.base import Node, NodeDriver, NodeLocation, NodeSize
-from libcloud.compute.base import NodeImage, StorageVolume
+from libcloud.compute.base import NodeImage, StorageVolume, VolumeSnapshot
 from libcloud.compute.base import UuidMixin
 from libcloud.compute.types import NodeState
 from libcloud.common.types import LibcloudError, MalformedResponseError
+from libcloud.common.exceptions import BaseHTTPError
+
+from collections import defaultdict
 
 __all__ = [
     'API_VERSION',
@@ -40,41 +39,52 @@ __all__ = [
     'ProfitBricksNodeDriver',
     'Datacenter',
     'ProfitBricksNetworkInterface',
-    'ProfitBricksAvailabilityZone'
+    'ProfitBricksFirewallRule',
+    'ProfitBricksLan',
+    'ProfitBricksLoadBalancer',
+    'ProfitBricksAvailabilityZone',
+    'ProfitBricksIPBlock'
 ]
 
 API_HOST = 'api.profitbricks.com'
-API_VERSION = '/1.3/'
+API_VERSION = '/cloudapi/v3/'
 
 
-class ProfitBricksResponse(XmlResponse):
+class ProfitBricksResponse(JsonResponse):
     """
     ProfitBricks response parsing.
     """
     def parse_error(self):
+        http_code = None
+        fault_code = None
+        message = None
         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
+            body = json.loads(self.body)
+            if 'httpStatus' in body:
+                http_code = body['httpStatus']
             else:
-                fault_code = None
-            if ET.iselement(e[0].find('message')):
-                message = e[0].find('message').text
+                http_code = 'unknown'
+
+            if 'messages' in body:
+                message = ', '.join(list(map(
+                    lambda item: item['message'], body['messages'])))
+                fault_code = ', '.join(list(map(
+                    lambda item: item['errorCode'], body['messages'])))
             else:
-                message = None
+                message = 'No messages returned.'
+                fault_code = 'unknown'
+        except Exception:
+            raise MalformedResponseError('Failed to parse Json',
+                                         body=self.body,
+                                         driver=ProfitBricksNodeDriver)
 
-        return LibcloudError('HTTP Code: %s, Fault Code: %s, Message: %s' %
-                             (http_code, fault_code, message), driver=self)
+        return LibcloudError(
+            '''
+                HTTP Code: %s,
+                Fault Code(s): %s,
+                Message(s): %s
+            '''
+            % (http_code, fault_code, message), driver=self)
 
 
 class ProfitBricksConnection(ConnectionUserAndKey):
@@ -85,56 +95,53 @@ class ProfitBricksConnection(ConnectionUserAndKey):
     api_prefix = API_VERSION
     responseCls = ProfitBricksResponse
 
-    # Supporting xml + lxml is funky :S
-    SOAPENV_NAMESPACE = 'http://schemas.xmlsoap.org/soap/envelope/'
-    SOAPENV = '{%s}' % SOAPENV_NAMESPACE
-    WS_NAMESPACE = 'http://ws.api.profitbricks.com/'
-    WS = '{%s}' % WS_NAMESPACE
-    NSMAP = {
-        'soapenv': SOAPENV_NAMESPACE,
-        'ws': WS_NAMESPACE,
-    }
-
     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(self.SOAPENV + 'Envelope',
-                              self.NSMAP, **self.NSMAP)
-        ET.SubElement(soap_env, self.SOAPENV + 'Header')
-        soap_body = ET.SubElement(soap_env, self.SOAPENV + 'Body')
-        soap_req_body = ET.SubElement(soap_body, self.WS + 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
+        '''
+        If a string is passed in, just return it
+        or else if a dict is passed in, encode it
+        as a json string.
+        '''
+        if type(data) is str:
+            return data
 
-        soap_post = ET.tostring(soap_env)
+        elif type(data) is dict:
+            return json.dumps(data)
 
-        return soap_post
+        else:
+            return ''
 
     def request(self, action, params=None, data=None, headers=None,
-                method='POST', raw=False):
-        action = self.api_prefix + action
+                method='GET', raw=False, with_full_url=False):
+
+        '''
+        Some requests will use the href attribute directly.
+        If this is not the case, then we should formulate the
+        url based on the action specified.
+        If we are using a full url, we need to remove the
+        host and protocol components.
+        '''
+        if not with_full_url or with_full_url is False:
+            action = self.api_prefix + action
+        else:
+            action = action.replace(
+                'https://{host}'.format(host=self.host),
+                ''
+            )
 
-        return super(ProfitBricksConnection, self).request(action=action,
-                                                           params=params,
-                                                           data=data,
-                                                           headers=headers,
-                                                           method=method,
-                                                           raw=raw)
+        return super(ProfitBricksConnection, self).request(
+            action=action,
+            params=params,
+            data=data,
+            headers=headers,
+            method=method,
+            raw=raw
+        )
 
 
 class Datacenter(UuidMixin):
@@ -145,17 +152,26 @@ class Datacenter(UuidMixin):
     :param      id: The datacenter ID.
     :type       id: ``str``
 
+    :param      href: The datacenter href.
+    :type       href: ``str``
+
     :param      name: The datacenter name.
     :type       name: ``str``
 
-    :param version: Datacenter version.
-    :type version: ``str``
+    :param      version: Datacenter version.
+    :type       version: ``str``
+
+    :param      driver: ProfitBricks Node Driver.
+    :type       driver: :class:`ProfitBricksNodeDriver`
 
+    :param      extra: Extra properties for the Datacenter.
+    :type       extra: ``dict``
 
     Note: This class is ProfitBricks specific.
     """
-    def __init__(self, id, name, version, driver, extra=None):
+    def __init__(self, id, href, name, version, driver, extra=None):
         self.id = str(id)
+        self.href = href
         self.name = name
         self.version = version
         self.driver = driver
@@ -164,8 +180,8 @@ class Datacenter(UuidMixin):
 
     def __repr__(self):
         return ((
-            '<Datacenter: id=%s, name=%s, version=%s, driver=%s> ...>')
-            % (self.id, self.name, self.version,
+            '<Datacenter: id=%s, href=%s name=%s, version=%s, driver=%s> ...>')
+            % (self.id, self.href, self.name, self.version,
                 self.driver.name))
 
 
@@ -180,20 +196,141 @@ class ProfitBricksNetworkInterface(object):
     :param      name: The network interface name.
     :type       name: ``str``
 
+    :param      href: The network interface href.
+    :type       href: ``str``
+
     :param      state: The network interface name.
     :type       state: ``int``
 
+    :param      extra: Extra properties for the network interface.
+    :type       extra: ``dict``
+
+    Note: This class is ProfitBricks specific.
+    """
+    def __init__(self, id, name, href, state, extra=None):
+        self.id = id
+        self.name = name
+        self.href = href
+        self.state = state
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (('<ProfitBricksNetworkInterface: id=%s, name=%s, href=%s>')
+                % (self.id, self.name, self.href))
+
+
+class ProfitBricksFirewallRule(object):
+    """
+    Extension class which stores information about a ProfitBricks
+    firewall rule.
+
+    :param      id: The firewall rule ID.
+    :type       id: ``str``
+
+    :param      name: The firewall rule name.
+    :type       name: ``str``
+
+    :param      href: The firewall rule href.
+    :type       href: ``str``
+
+    :param      state: The current state of the firewall rule.
+    :type       state: ``int``
+
+    :param      extra: Extra properties for the firewall rule.
+    :type       extra: ``dict``
+
+    Note: This class is ProfitBricks specific.
+
+    """
+
+    def __init__(self, id, name, href, state, extra=None):
+        self.id = id
+        self.name = name
+        self.href = href
+        self.state = state
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (('<ProfitBricksFirewallRule: id=%s, name=%s, href=%s>')
+                % (self.id, self.name, self.href))
+
+
+class ProfitBricksLan(object):
+    """
+    Extension class which stores information about a
+    ProfitBricks LAN
+
+    :param      id: The ID of the lan.
+    :param      id: ``str``
+
+    :param      name: The name of the lan.
+    :type       name: ``str``
+
+    :param      href: The lan href.
+    :type       href: ``str``
+
+    :param      is_public: If public, the lan faces the public internet.
+    :type       is_public: ``bool``
+
+    :param      state: The current state of the lan.
+    :type       state: ``int``
+
+    :param      extra: Extra properties for the lan.
+    :type       extra: ``dict``
+
     Note: This class is ProfitBricks specific.
+
+    """
+
+    def __init__(self, id, name, href, is_public, state, driver, extra=None):
+        self.id = id
+        self.name = name
+        self.href = href
+        self.is_public = is_public
+        self.state = state
+        self.driver = driver
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (('<ProfitBricksLan: id=%s, name=%s, href=%s>')
+                % (self.id, self.name, self.href))
+
+
+class ProfitBricksLoadBalancer(object):
+    """
+    Extention class which stores information about a
+    ProfitBricks load balancer
+
+    :param      id: The ID of the load balancer.
+    :param      id: ``str``
+
+    :param      name: The name of the load balancer.
+    :type       name: ``str``
+
+    :param      href: The load balancer href.
+    :type       href: ``str``
+
+    :param      state: The current state of the load balancer.
+    :type       state: ``int``
+
+    :param      extra: Extra properties for the load balancer.
+    :type       extra: ``dict``
+
+    Note: This class is ProfitBricks specific
+
     """
-    def __init__(self, id, name, state, extra=None):
+
+    def __init__(self, id, name, href, state, driver, extra=None):
         self.id = id
         self.name = name
+        self.href = href
         self.state = state
+        self.driver = driver
         self.extra = extra or {}
 
     def __repr__(self):
-        return (('<ProfitBricksNetworkInterface: id=%s, name=%s>')
-                % (self.id, self.name))
+        return (('ProfitBricksLoadbalancer: id=%s, name=%s, href=%s>')
+                % (self.id, self.name, self.href))
 
 
 class ProfitBricksAvailabilityZone(object):
@@ -201,6 +338,9 @@ class ProfitBricksAvailabilityZone(object):
     Extension class which stores information about a ProfitBricks
     availability zone.
 
+    :param      name: The availability zone name.
+    :type       name: ``str``
+
     Note: This class is ProfitBricks specific.
     """
 
@@ -212,6 +352,64 @@ class ProfitBricksAvailabilityZone(object):
                 % (self.name))
 
 
+class ProfitBricksIPBlock(object):
+    """
+    Extension class which stores information about a ProfitBricks
+    IP block.
+
+    :param      id: The ID of the IP block.
+    :param      id: ``str``
+
+    :param      name: The name of the IP block.
+    :type       name: ``str``
+
+    :param      href: The IP block href.
+    :type       href: ``str``
+
+    :param      location: The location of the IP block.
+    :type       location: ``str``
+
+    :param      size: Number of IP addresses in the block.
+    :type       size: ``int``
+
+    :param      ips: A collection of IPs associated with the block.
+    :type       ips: ``list``
+
+    :param      state: The current state of the IP block.
+    :type       state: ``int``
+
+    :param      extra: Extra properties for the IP block.
+    :type       extra: ``dict``
+
+    Note: This class is ProfitBricks specific
+    """
+
+    def __init__(
+        self, id, name, href, location,
+        size, ips, state, driver,
+        extra=None
+    ):
+
+        self.id = id
+        self.name = name
+        self.href = href
+        self.location = location
+        self.size = size
+        self.ips = ips
+        self.state = state
+        self.driver = driver
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (
+            (
+                '<ProfitBricksIPBlock: id=%s,'
+                'name=%s, href=%s,location=%s, size=%s>'
+            )
+            % (self.id, self.name, self.href, self.location, self.size)
+        )
+
+
 class ProfitBricksNodeDriver(NodeDriver):
     """
     Base ProfitBricks node driver.
@@ -222,26 +420,21 @@ class ProfitBricksNodeDriver(NodeDriver):
     type = Provider.PROFIT_BRICKS
 
     PROVISIONING_STATE = {
-        'INACTIVE': NodeState.PENDING,
-        'INPROCESS': NodeState.PENDING,
         'AVAILABLE': NodeState.RUNNING,
-        'DELETED': NodeState.TERMINATED,
+        'BUSY': NodeState.PENDING,
+        'INACTIVE': NodeState.PENDING
     }
 
     NODE_STATE_MAP = {
         'NOSTATE': NodeState.UNKNOWN,
         'RUNNING': NodeState.RUNNING,
         'BLOCKED': NodeState.STOPPED,
-        'PAUSE': NodeState.STOPPED,
-        'SHUTDOWN': NodeState.PENDING,
+        'PAUSE': NodeState.PAUSED,
+        'SHUTDOWN': NodeState.STOPPING,
         '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'},
+        'CRASHED': NodeState.ERROR,
+        'AVAILABLE': NodeState.RUNNING,
+        'BUSY': NodeState.PENDING
     }
 
     AVAILABILITY_ZONE = {
@@ -320,6 +513,7 @@ class ProfitBricksNodeDriver(NodeDriver):
         """
         Lists all sizes
 
+        :return: A list of all configurable node sizes.
         :rtype: ``list`` of :class:`NodeSize`
         """
         sizes = []
@@ -330,42 +524,67 @@ class ProfitBricksNodeDriver(NodeDriver):
 
         return sizes
 
-    def list_images(self):
+    def list_images(self, image_type=None, is_public=True):
         """
-        List all images.
+        List all images with an optional filter.
 
-        :rtype: ``list`` of :class:`NodeImage`
-        """
+        :param  image_type: The image type (HDD, CDROM)
+        :type   image_type: ``str``
+
+        :param  is_public: Image is public
+        :type   is_public: ``bool``
 
-        action = 'getAllImages'
-        body = {'action': action}
+        :return: ``list`` of :class:`NodeImage`
+        :rtype: ``list``
+        """
+        response = self.connection.request(
+            action='images',
+            params={'depth': 1},
+            method='GET'
+        )
 
-        return self._to_images(self.connection.request(action=action,
-                               data=body, method='POST').object)
+        return self._to_images(response.object, image_type, is_public)
 
     def list_locations(self):
         """
         List all locations.
-        """
-        locations = []
 
-        for key, values in self.REGIONS.items():
-            location = self._to_location(values)
-            locations.append(location)
+        :return: ``list`` of :class:`NodeLocation`
+        :rtype: ``list``
+        """
+        return self._to_locations(self.connection.request(
+            action='locations',
+            params={'depth': 1},
+            method='GET').object
+        )
 
-        return locations
+    """
+    Node functions
+    """
 
     def list_nodes(self):
         """
         List all nodes.
 
-        :rtype: ``list`` of :class:`Node`
+        :return: ``list`` of :class:`Node`
+        :rtype: ``list``
         """
-        action = 'getAllServers'
-        body = {'action': action}
+        datacenters = self.ex_list_datacenters()
+        nodes = list()
+
+        for datacenter in datacenters:
+            servers_href = datacenter.extra['entities']['servers']['href']
+            response = self.connection.request(
+                action=servers_href,
+                params={'depth': 3},
+                method='GET',
+                with_full_url=True
+            )
+
+            mapped_nodes = self._to_nodes(response.object)
+            nodes += mapped_nodes
 
-        return self._to_nodes(self.connection.request(action=action,
-                              data=body, method='POST').object)
+        return nodes
 
     def reboot_node(self, node):
         """
@@ -373,20 +592,25 @@ class ProfitBricksNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        action = 'resetServer'
-        body = {'action': action,
-                'serverId': node.id
-                }
+        action = node.extra['href'] + '/reboot'
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='POST',
+            with_full_url=True
+        )
 
         return True
 
-    def create_node(self, name, image, size=None, location=None,
-                    volume=None, ex_datacenter=None, ex_internet_access=True,
-                    ex_availability_zone=None, ex_ram=None, ex_cores=None,
-                    ex_disk=None, **kwargs):
+    def create_node(
+        self, name, image=None, size=None, location=None,
+        ex_cpu_family=None, volume=None, ex_datacenter=None,
+        ex_network_interface=True, ex_internet_access=True,
+        ex_exposed_public_ports=[], ex_exposed_private_ports=[22],
+        ex_availability_zone=None, ex_ram=None, ex_cores=None,
+        ex_disk=None, ex_password=None, ex_ssh_keys=None,
+        ex_bus_type=None, ex_disk_type=None, **kwargs
+    ):
         """
         Creates a node.
 
@@ -394,52 +618,111 @@ class ProfitBricksNodeDriver(NodeDriver):
         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  name: The name for the new node.
+        :param  type: ``str``
 
-        :param location: The location of the new data center
+        :param  image: The image to create the node with.
+        :type   image: :class:`NodeImage`
+
+        :param  size: Standard configured size offered by
+            ProfitBricks - containing configuration for the
+            number of cpu cores, amount of ram and disk size.
+        :param  size: :class:`NodeSize`
+
+        :param  location: The location of the new data center
             if one is not supplied.
-        :type location: : :class:`NodeLocation`
+        :type   location: :class:`NodeLocation`
+
+        :param  ex_cpu_family: The CPU family to use (AMD_OPTERON, INTEL_XEON)
+        :type   ex_cpu_family: ``str``
+
+        :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
+        :param  ex_datacenter: If you've already created the DC then pass
                            it in.
-        :type ex_datacenter: :class:`Datacenter`
+        :type   ex_datacenter: :class:`Datacenter`
+
+        :param  ex_network_interface: Create with a network interface.
+        :type   ex_network_interface: : ``bool``
+
+        :param  ex_internet_access: Configure public Internet access.
+        :type   ex_internet_access: : ``bool``
+
+        :param  ex_exposed_public_ports: Ports to be opened
+                                        for the public nic.
+        :param  ex_exposed_public_ports: ``list`` of ``int``
+
+        :param  ex_exposed_private_ports: Ports to be opened
+                                        for the private nic.
+        :param  ex_exposed_private_ports: ``list`` of ``int``
 
-        :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_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_ram: The amount of ram required.
-        :type ex_ram: : ``int``
+        :param  ex_cores: The number of cores required.
+        :type   ex_cores: ``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``
 
-        :param ex_disk: The amount of disk required.
-        :type ex_disk: : ``int``
+        :param  ex_password: The password for the volume.
+        :type   ex_password: ``str``
+
+        :param  ex_ssh_keys: Optional SSH keys for the volume.
+        :type   ex_ssh_keys: ``list`` of ``str``
+
+        :param  ex_bus_type: Volume bus type (VIRTIO, IDE).
+        :type   ex_bus_type: ``str``
+
+        :param  ex_disk_type: Volume disk type (SSD, HDD).
+        :type   ex_disk_type: ``str``
 
         :return:    Instance of class ``Node``
-        :rtype:     :class:`Node`
+        :rtype:     :class: `Node`
         """
+
+        """
+        If we have a volume we can determine the DC
+        that it belongs to and set accordingly.
+        """
+        if volume is not None:
+            dc_url_pruned = volume.extra['href'].split('/')[:-2]
+            dc_url = '/'.join(item for item in dc_url_pruned)
+            ex_datacenter = self.ex_describe_datacenter(
+                ex_href=dc_url
+            )
+
         if not ex_datacenter:
             '''
-            We generate a name from the server name passed into the function.
+            Determine location for new DC by
+            getting the location of the image.
             '''
+            if not location:
+                if image is not None:
+                    location = self.ex_describe_location(
+                        ex_location_id=image.extra['location']
+                    )
 
-            'Creating a Datacenter for the node since one was not provided.'
+            '''
+            Creating a Datacenter for the node
+            since one was not provided.
+            '''
             new_datacenter = self._create_new_datacenter_for_node(
                 name=name,
                 location=location
             )
-            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
+            '''
+            Then wait for the operation to finish,
+            assigning the full data center on completion.
+            '''
+            ex_datacenter = self._wait_for_datacenter_state(
+                datacenter=new_datacenter
+            )
 
         if not size:
             if not ex_ram:
@@ -451,7 +734,20 @@ class ProfitBricksNodeDriver(NodeDriver):
                                  'NodeSize or specify ex_cores as '
                                  'an extra parameter.')
 
-        if not volume:
+        '''
+        If passing in an image we need
+        to enfore a password or ssh keys.
+        '''
+        if not volume and image is not None:
+            if ex_password is None and ex_ssh_keys is None:
+                raise ValueError(
+                    (
+                        'When creating a server without a '
+                        'volume, you need to specify either an '
+                        'array of SSH keys or a volume password.'
+                    )
+                )
+
             if not size:
                 if not ex_disk:
                     raise ValueError('You need to either pass a '
@@ -464,8 +760,15 @@ class ProfitBricksNodeDriver(NodeDriver):
         for your specific use.
         '''
 
-        if not ex_disk:
-            ex_disk = size.disk
+        if image is not None:
+            if not ex_disk:
+                ex_disk = size.disk
+
+        if not ex_disk_type:
+            ex_disk_type = 'HDD'
+
+        if not ex_bus_type:
+            ex_bus_type = 'VIRTIO'
 
         if not ex_ram:
             ex_ram = size.ram
@@ -473,62 +776,148 @@ class ProfitBricksNodeDriver(NodeDriver):
         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
+        action = ex_datacenter.href + '/servers'
+        body = {
+            'properties': {
+                'name': name,
+                'ram': ex_ram,
+                'cores': ex_cores
+            },
+            'entities': {
+                'volumes': {
+                    'items': []
+                }
+            }
+        }
 
         '''
-        Create a StorageVolume that can be attached to the
-        server when it is created.
+        If we are using a pre-existing storage volume.
         '''
-        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 volume is not None:
+            body['entities']['volumes']['items'].append({'id': volume.id})
+        elif image is not None:
+            new_volume = {
+                'properties': {
+                    'size': ex_disk,
+                    'name': name + ' - volume',
+                    'image': image.id,
+                    'type': ex_disk_type,
+                    'bus': ex_bus_type
                 }
+            }
+
+            if ex_password is not None:
+                new_volume['properties']['imagePassword'] = ex_password
+
+            if ex_ssh_keys is not None:
+                new_volume['properties']['sshKeys'] = ex_ssh_keys
+
+            body['entities']['volumes']['items'].append(new_volume)
+
+        if ex_network_interface is True:
+            body['entities']['nics'] = {}
+            body['entities']['nics']['items'] = list()
 
-        if ex_availability_zone:
-            body['availabilityZone'] = ex_availability_zone.name
+            '''
+            Get the LANs for the data center this node
+            will be provisioned at.
+            '''
+            dc_lans = self.ex_list_lans(
+                datacenter=ex_datacenter
+            )
+
+            private_lans = [lan for lan in dc_lans if lan.is_public is False]
+            private_lan = None
+
+            if private_lans:
+                private_lan = private_lans[0]
+
+            if private_lan is not None:
+                private_nic = {
+                    'properties': {
+                        'name': name + ' - private nic',
+                        'lan': private_lan.id,
+                    },
+                    'entities': {
+                        'firewallrules': {
+                            'items': []
+                        }
+                    }
+                }
 
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        nodes = self._to_nodes(data)
-        return nodes[0]
+                for port in ex_exposed_private_ports:
+                    private_nic['entities']['firewallrules']['items'].append(
+                        {
+                            'properties': {
+                                'name': (
+                                    '{name} - firewall rule:{port}'.format(
+                                        name=name, port=port
+                                    )
+                                ),
+                                'protocol': 'TCP',
+                                'portRangeStart': port,
+                                'portRangeEnd': port
+                            }
+                        }
+                    )
+
+                body['entities']['nics']['items'].append(private_nic)
+
+            if ex_internet_access is not None and ex_internet_access is True:
+                public_lans = [lan for lan in dc_lans if lan.is_public]
+                public_lan = None
+
+                if public_lans:
+                    public_lan = public_lans[0]
+
+                if public_lan is not None:
+                    pub_nic = {
+                        'properties': {
+                            'name': name + ' - public nic',
+                            'lan': public_lan.id,
+                        },
+                        'entities': {
+                            'firewallrules': {
+                                'items': []
+                            }
+                        }
+                    }
+
+                    for port in ex_exposed_public_ports:
+                        pub_nic['entities']['firewallrules']['items'].append(
+                            {
+                                'properties': {
+                                    'name': (
+                                        '{name} - firewall rule:{port}'.format(
+                                            name=name, port=port
+                                        )
+                                    ),
+                                    'protocol': 'TCP',
+                                    'portRangeStart': port,
+                                    'portRangeEnd': port
+                                }
+                            }
+                        )
+
+                    body['entities']['nics']['items'].append(pub_nic)
+
+        if ex_cpu_family is not None:
+            body['properties']['cpuFamily'] = ex_cpu_family
+
+        if ex_availability_zone is not None:
+            body['properties']['availabilityZone'] = ex_availability_zone.name
+
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'application/json'
+            },
+            data=body,
+            method='POST',
+            with_full_url=True
+        )
+
+        return self._to_node(response.object, response.headers)
 
     def destroy_node(self, node, ex_remove_attached_disks=False):
         """
@@ -542,13 +931,18 @@ class ProfitBricksNodeDriver(NodeDriver):
 
         :rtype:     : ``bool``
         """
-        action = 'deleteServer'
-        body = {'action': action,
-                'serverId': node.id
-                }
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        if ex_remove_attached_disks is True:
+            for volume in self.ex_list_attached_volumes(node):
+                self.destroy_volume(volume)
+
+        action = node.extra['href']
+
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
@@ -558,104 +952,190 @@ class ProfitBricksNodeDriver(NodeDriver):
 
     def list_volumes(self):
         """
-        Lists all voumes.
+        List all volumes attached to a data center.
+
+        :return: ``list`` of :class:`StorageVolume`
+        :rtype: ``list``
         """
-        action = 'getAllStorages'
-        body = {'action': action}
+        datacenters = self.ex_list_datacenters()
+        volumes = list()
 
-        return self._to_volumes(self.connection.request(action=action,
-                                                        data=body,
-                                                        method='POST').object)
+        for datacenter in datacenters:
+            volumes_href = datacenter.extra['entities']['volumes']['href']
 
-    def attach_volume(self, node, volume, device=None, ex_bus_type=None):
-        """
-        Attaches a volume.
+            response = self.connection.request(
+                action=volumes_href,
+                params={'depth': 3},
+                method='GET',
+                with_full_url=True
+            )
 
-        :param volume: The volume you're attaching.
-        :type volume: :class:`StorageVolume`
+            mapped_volumes = self._to_volumes(response.object)
+            volumes += mapped_volumes
+
+        return volumes
 
-        :param node: The node to which you're attaching the volume.
-        :type node: :class:`Node`
+    def attach_volume(self, node, volume):
+        """
+        Attaches a volume.
 
-        :param device: The device number order.
-        :type device: : ``int``
+        :param  node: The node to which you're attaching the volume.
+        :type   node: :class:`Node`
 
-        :param ex_bus_type: Bus type. Either IDE or VIRTIO (default).
-        :type ex_bus_type: ``str``
+        :param  volume: The volume you're attaching.
+        :type   volume: :class:`StorageVolume`
 
         :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
+        action = node.extra['href'] + '/volumes'
+        body = {
+            'id': volume.id
+        }
 
-    def create_volume(self, size, name=None,
-                      ex_datacenter=None, ex_image=None, ex_password=None):
+        data = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'application/json'
+            },
+            data=body,
+            method='POST',
+            with_full_url=True
+        )
+
+        return self._to_volume(data.object, data.headers)
+
+    def create_volume(
+        self,
+        size,
+        image,
+        ex_datacenter,
+        name=None,
+        ex_type=None,
+        ex_bus_type=None,
+        ex_ssh_keys=None,
+        ex_password=None,
+        ex_availability_zone=None
+    ):
         """
         Creates a volume.
 
-        :param ex_datacenter: The datacenter you're placing
+        :param  size: The size of the volume in GB.
+        :type   size: ``int``
+
+        :param  image: The OS image for the volume.
+        :type   image: :class:`NodeImage`
+
+        :param  ex_datacenter: The datacenter you're placing
                               the storage in. (req)
-        :type ex_datacenter: :class:`Datacenter`
+        :type   ex_datacenter: :class:`Datacenter`
+
+        :param  name: The name to be given to the volume.
+        :param  name: ``str``
+
+        :param  ex_type: The type to be given to the volume (SSD or HDD).
+        :param  ex_type: ``str``
+
+        :param  ex_bus_type: Bus type. Either IDE or VIRTIO (default).
+        :type   ex_bus_type: ``str``
 
-        :param ex_image: The OS image for the volume.
-        :type ex_image: :class:`NodeImage`
+        :param  ex_ssh_keys: Optional SSH keys.
+        :type   ex_ssh_keys: ``dict``
 
-        :param ex_password: Optional password for root.
-        :type ex_password: : ``str``
+        :param  ex_password: Optional password for root.
+        :type   ex_password: ``str``
+
+        :param  ex_availability_zone: Volume Availability Zone.
+        :type   ex_availability_zone: ``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
+        if not ex_datacenter:
+            raise ValueError('You need to specify a data center'
+                             ' to attach this volume to.')
+
+        if not image:
+            raise ValueError('You need to specify an image'
+                             ' to create this volume from.')
+
+        if image.extra['image_type'] != 'HDD':
+            raise ValueError('Invalid type of {image_type} specified for '
+                             '{image_name}, which needs to be of type HDD'
+                             .format(image_type=image.extra['image_type'],
+                                     image_name=image.name))
+
+        if ex_datacenter.extra['location'] != image.extra['location']:
+            raise ValueError(
+                'The image {image_name} '
+                '(location: {image_location}) you specified '
+                'is not available at the data center '
+                '{datacenter_name} '
+                '(location: {datacenter_location}).'
+                .format(
+                    image_name=image.extra['name'],
+                    datacenter_name=ex_datacenter.extra['name'],
+                    image_location=image.extra['location'],
+                    datacenter_location=ex_datacenter.extra['location']
+                )
+            )
 
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        volumes = self._to_volumes(data)
-        return volumes[0]
+        action = ex_datacenter.href + '/volumes'
+        body = {
+            'properties': {
+                'size': size,
+                'image': image.id
+            }
+        }
 
-    def detach_volume(self, volume):
+        if name is not None:
+            body['properties']['name'] = name
+        if ex_type is not None:
+            body['properties']['type'] = ex_type
+        if ex_bus_type is not None:
+            body['properties']['bus'] = ex_bus_type
+        if ex_ssh_keys is not None:
+            body['properties']['sshKeys'] = ex_ssh_keys
+        if ex_password is not None:
+            body['properties']['imagePassword'] = ex_password
+        if ex_availability_zone is not None:
+            body['properties']['availabilityZone'] = ex_availability_zone
+
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'application/json'
+            },
+            data=body,
+            method='POST',
+            with_full_url=True
+        )
+
+        return self._to_volume(response.object, response.headers)
+
+    def detach_volume(self, node, volume):
         """
         Detaches a volume.
 
+        :param  node: The node to which you're detaching the volume.
+        :type   node: :class:`Node`
+
         :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
-                }
+        action = node.extra['href'] + '/volumes/{volume_id}'.format(
+            volume_id=volume.id
+        )
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
@@ -663,121 +1143,139 @@ class ProfitBricksNodeDriver(NodeDriver):
         """
         Destroys a volume.
 
-        :param volume: The volume you're attaching.
+        :param volume: The volume you're destroying.
         :type volume: :class:`StorageVolume`
 
         :rtype:     : ``bool``
         """
-        action = 'deleteStorage'
-        body = {'action': action,
-                'storageId': volume.id}
+        action = volume.extra['href']
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
-    def ex_update_volume(self, volume, storage_name=None, size=None):
+    """
+    Volume snapshot functions
+    """
+
+    def list_snapshots(self):
         """
-        Updates a volume.
+        Fetches as a list of all snapshots
 
-        :param volume: The volume you're attaching..
-        :type volume: :class:`StorageVolume`
+        :return:    ``list`` of class ``VolumeSnapshot``
+        :rtype:     `list`
+        """
 
-        :param storage_name: The name of the volume.
-        :type storage_name: : ``str``
+        response = self.connection.request(
+            action='/snapshots',
+            params={'depth': 3},
+            method='GET'
+        )
 
-        :param size: The desired size.
-        :type size: ``int``
+        return self._to_snapshots(response.object)
 
-        :rtype:     : ``bool``
+    def create_volume_snapshot(self, volume):
         """
-        action = 'updateStorage'
-        body = {'action': action,
-                'request': 'true',
-                'storageId': volume.id
-                }
+        Creates a snapshot for a volume
 
-        if storage_name:
-            body['storageName'] = storage_name
-        if size:
-            body['size'] = str(size)
+        :param  volume: The volume you're creating a snapshot for.
+        :type   volume: :class:`StorageVolume`
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        :return:    Instance of class ``VolumeSnapshot``
+        :rtype:     :class:`VolumeSnapshot`
+        """
 
-        return True
+        action = volume.extra['href'] + '/create-snapshot'
+
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'application/x-www-form-urlencoded'
+            },
+            method='POST',
+            with_full_url=True
+        )
+
+        return self._to_snapshot(response.object, response.headers)
 
-    def ex_describe_volume(self, volume_id):
+    def destroy_volume_snapshot(self, snapshot):
         """
-        Describes a volume.
+        Delete a snapshot
 
-        :param volume_id: The ID of the volume you're describing.
-        :type volume_id: :class:`StorageVolume`
+        :param  snapshot: The snapshot you wish to delete.
+        :type:  snapshot: :class:`VolumeSnapshot`
 
-        :return:    Instance of class ``StorageVolume``
-        :rtype:     :class:`StorageVolume`
+        :rtype  ``bool``
         """
-        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]
+        action = snapshot.extra['href']
+
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
+
+        return True
 
     """
     Extension Functions
     """
 
-    ''' Server Extension Functions
-    '''
+    """
+    Server Extension Functions
+    """
+
     def ex_stop_node(self, node):
         """
         Stops a node.
 
         This also deallocates the public IP space.
 
-        :param node: The node you wish to halt.
-        :type node: :class:`Node`
+        :param  node: The node you wish to halt.
+        :type   node: :class:`Node`
 
         :rtype:     : ``bool``
         """
-        action = 'stopServer'
-        body = {'action': action,
-                'serverId': node.id
-                }
+        action = node.extra['href'] + '/stop'
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='POST',
+            with_full_url=True
+        )
 
         return True
 
     def ex_start_node(self, node):
         """
-        Starts a volume.
+        Starts a node.
 
-        :param node: The node you wish to start.
-        :type node: :class:`Node`
+        :param  node: The node you wish to start.
+        :type   node: :class:`Node`
 
-        :rtype:     : ``bool``
+        :rtype: ``bool``
         """
-        action = 'startServer'
-        body = {'action': action,
-                'serverId': node.id
-                }
+        action = node.extra['href'] + '/start'
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='POST',
+            with_full_url=True
+        )
 
         return True
 
     def ex_list_availability_zones(self):
         """
         Returns a list of availability zones.
+
+        :return: ``list`` of :class:`ProfitBricksAvailabilityZone`
+        :rtype: ``list``
         """
 
         availability_zones = []
@@ -792,100 +1290,219 @@ class ProfitBricksNodeDriver(NodeDriver):
 
         return availability_zones
 
-    def ex_describe_node(self, node):
+    def ex_list_attached_volumes(self, node):
         """
-        Describes a node.
+        Returns a list of attached volumes for a server
 
-        :param node: The node you wish to describe.
-        :type node: :class:`Node`
+        :param  node: The node with the attached volumes.
+        :type   node: :class:`Node`
 
-        :return:    Instance of class ``Node``
-        :rtype:     :class:`Node`
+        :return:    ``list`` of :class:`StorageVolume`
+        :rtype:     ``list``
         """
-        action = 'getServer'
-        body = {'action': action,
-                'serverId': node.id
-                }
+        action = node.extra['entities']['volumes']['href']
+        response = self.connection.request(
+            action=action,
+            params={'depth': 3},
+            method='GET',
+            with_full_url=True
+        )
 
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        nodes = self._to_nodes(data)
-        return nodes[0]
+        return self._to_volumes(response.object)
 
-    def ex_update_node(self, node, name=None, cores=None,
-                       ram=None, availability_zone=None):
+    def ex_describe_node(
+        self,
+        ex_href=None,
+        ex_datacenter_id=None,
+        ex_node_id=None
+    ):
         """
-        Updates a node.
+        Fetches a node directly by href or
+        by a combination of the datacenter
+        ID and the server ID.
 
-        :param cores: The number of CPUs the node should have.
-        :type device: : ``int``
+        :param  ex_href: The href (url) of the node you wish to describe.
+        :type   ex_href: ``str``
 
-        :param ram: The amount of ram the machine should have.
-        :type ram: : ``int``
+        :param  ex_datacenter_id: The ID for the data center.
+        :type   ex_datacenter_id: ``str``
 
-        :param ex_availability_zone: Update the availability zone.
-        :type ex_availability_zone: :class:`ProfitBricksAvailabilityZone`
+        :param  ex_node_id: The ID for the node (server).
+        :type   ex_node_id: ``str``
 
-        :rtype:     : ``bool``
+        :return:    Instance of class ``Node``
+        :rtype:     :class:`Node`
         """
-        action = 'updateServer'
 
-        body = {'action': action,
-                'request': 'true',
-                'serverId': node.id
-                }
+        use_full_url = True
 
-        if name:
-            body['serverName'] = name
+        if ex_href is None:
+            if ex_datacenter_id is None or ex_node_id is None:
+                raise ValueError(
+                    'IDs for the data center and node are required.'
+                )
+            else:
+                use_full_url = False
+                ex_href = (
+                    'datacenters/{datacenter_id}/'
+                    'servers/{server_id}'
+                ).format(
+                    datacenter_id=ex_datacenter_id,
+                    server_id=ex_node_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            params={'depth': 3},
+            with_full_url=use_full_url
+        )
+
+        return self._to_node(response.object)
 
-        if cores:
-            body['cores'] = str(cores)
+    def ex_update_node(self, node, name=None, cores=None,
+                       ram=None, availability_zone=None,
+                       ex_licence_type=None, ex_boot_volume=None,
+                       ex_boot_cdrom=None, ex_cpu_family=None):
+        """
+        Updates a node.
 
-        if ram:
-            body['ram'] = str(ram)
+        :param  node: The node you wish to update.
+        :type   node: :class:`Node`
 
-        if availability_zone:
-            body['availabilityZone'] = availability_zone.name
+        :param  name: The new name for the node.
+        :type   name: ``str``
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        :param  cores: The number of CPUs the node should have.
+        :type   cores: : ``int``
 
-        return True
+        :param  ram: The amount of ram the node should have.
+        :type   ram: : ``int``
 
-    '''
-    Datacenter Extension Functions
-    '''
+        :param  availability_zone: Update the availability zone.
+        :type   availability_zone: :class:`ProfitBricksAvailabilityZone`
 
-    def ex_create_datacenter(self, name, location):
-        """
-        Creates a datacenter.
+        :param  ex_licence_type: Licence type (WINDOWS, LINUX, OTHER).
+        :type   ex_licence_type: ``str``
 
-        ProfitBricks has a concept of datacenters.
-        These represent buckets into which you
-        can place various compute resources.
+        :param  ex_boot_volume: Setting the new boot (HDD) volume.
+        :type   ex_boot_volume: :class:`StorageVolume`
 
-        :param name: The DC name.
-        :type name: : ``str``
+        :param  ex_boot_cdrom: Setting the new boot (CDROM) volume.
+        :type   ex_boot_cdrom: :class:`StorageVolume`
 
-        :param location: The DC region.
-        :type location: : ``str``
+        :param  ex_cpu_family: CPU family (INTEL_XEON, AMD_OPTERON).
+        :type   ex_cpu_family: ``str``
 
-        :return:    Instance of class ``Datacenter``
-        :rtype:     :class:`Datacenter`
+        :return:    Instance of class ``Node``
+        :rtype:     :class: `Node`
+        """
+        action = node.extra['href']
+        body = {}
+
+        if name is not None:
+            body['name'] = name
+
+        if cores is not None:
+            body['cores'] = cores
+
+        if ram is not None:
+            body['ram'] = ram
+
+        if availability_zone is not None:
+            body['availabilityZone'] = availability_zone.name
+
+        if ex_licence_type is not None:
+            body['licencetype'] = ex_licence_type
+
+        if ex_boot_volume is not None:
+            body['bootVolume'] = ex_boot_volume.id
+
+        if ex_boot_cdrom is not None:
+            body['bootCdrom'] = ex_boot_cdrom.id
+
+        if ex_cpu_family is not None:
+            body['allowReboot'] = True
+            body['cpuFamily'] = ex_cpu_family
+
+        response = self.connection.request(
+            action=action,
+            data=body,
+            headers={
+                'Content-Type':
+                'application/json'
+            },
+            method='PATCH',
+            with_full_url=True
+        )
+
+        return self._to_node(response.object, response.headers)
+
+    """
+    Data center Extension Functions
+    """
+
+    def ex_create_datacenter(
+        self,
+        name,
+        location,
+        description=None
+    ):
+        """
+        Creates a datacenter.
+
+        ProfitBricks has a concept of datacenters.
+        These represent buckets into which you
+        can place various compute resources.
+
+        :param  name: The datacenter name.
+        :type   name: : ``str``
+
+        :param  location: instance of class ``NodeLocation``.
+        :type   location: : ``NodeLocation``
+
+        :param  description: The datacenter description.
+        :type   description: : ``str``
+
+        :return:    Instance of class ``Datacenter``
+        :rtype:     :class:`Datacenter`
         """
-        action = 'createDataCenter'
+        body = {
+            'properties': {
+                'name': name,
+                'location': location.id
+            }
+        }
 
-        body = {'action': action,
-                'request': 'true',
-                'dataCenterName': name,
-                'location': location.lower()
+        if description is not None:
+            body['properties']['description'] = description
+
+        body['entities'] = defaultdict(dict)
+        body['entities']['lans']['items'] = [
+            {
+                'properties': {
+                    'name': name + ' - public lan',
+                    'public': True
+                }
+            },
+            {
+                'properties': {
+                    'name': name + ' - private lan',
+                    'public': False
                 }
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        datacenters = self._to_datacenters(data)
-        return datacenters[0]
+            }
+        ]
+
+        response = self.connection.request(
+            action='datacenters',
+            headers={
+                'Content-Type': 'application/json'
+            },
+            data=body,
+            method='POST'
+        )
+
+        return self._to_datacenter(response.object, response.headers)
 
     def ex_destroy_datacenter(self, datacenter):
         """
@@ -896,141 +1513,366 @@ class ProfitBricksNodeDriver(NodeDriver):
 
         :rtype:     : ``bool``
         """
-        action = 'deleteDataCenter'
-        body = {'action': action,
-                'dataCenterId': datacenter.id
-                }
+        action = datacenter.href
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
-    def ex_describe_datacenter(self, datacenter_id):
+    def ex_describe_datacenter(self, ex_href=None, ex_datacenter_id=None):
         """
-        Describes a datacenter.
+        Fetches the details for a data center.
+
+        :param  ex_href: The href for the data center
+                        you are describing.
+        :type   ex_href: ``str``
 
-        :param datacenter_id: The DC you are describing.
-        :type datacenter_id: ``str``
+        :param  ex_datacenter_id: The ID for the data cente
+                                you are describing.
+        :type   ex_datacenter_id: ``str``
 
         :return:    Instance of class ``Datacenter``
         :rtype:     :class:`Datacenter`
         """
 
-        action = 'getDataCenter'
-        body = {'action': action,
-                'dataCenterId': datacenter_id
-                }
+        use_full_url = True
 
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        datacenters = self._to_datacenters(data)
-        return datacenters[0]
+        if ex_href is None:
+            if ex_datacenter_id is None:
+                raise ValueError(
+                    'The data center ID is required.'
+                )
+            else:
+                use_full_url = False
+                ex_href = (
+                    'datacenters/{datacenter_id}'
+                ).format(
+                    datacenter_id=ex_datacenter_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            params={'depth': 3},
+            with_full_url=use_full_url
+        )
+
+        return self._to_datacenter(response.object)
 
     def ex_list_datacenters(self):
         """
         Lists all datacenters.
 
-        :return:    ``list`` of class ``Datacenter``
-        :rtype:     :class:`Datacenter`
+        :return: ``list`` of :class:`DataCenter`
+        :rtype: ``list``
         """
-        action = 'getAllDataCenters'
-        body = {'action': action}
+        response = self.connection.request(
+            action='datacenters',
+            params={'depth': 2},
+            method='GET'
+        )
 
-        return self._to_datacenters(self.connection.request(
-                                    action=action,
-                                    data=body,
-                                    method='POST').object)
+        return self._to_datacenters(response.object)
 
     def ex_rename_datacenter(self, datacenter, name):
         """
         Update a datacenter.
 
-        :param datacenter: The DC you are renaming.
-        :type datacenter: :class:`Datacenter`
+        :param  datacenter: The DC you are renaming.
+        :type   datacenter: :class:`Datacenter`
 
-        :param name: The DC name.
-        :type name: : ``str``
+        :param  name: The DC name.
+        :type   name: : ``str``
 
-        :rtype:     : ``bool``
+        :return:    Instance of class ``Datacenter``
+        :rtype:     :class:`Datacenter`
         """
-        action = 'updateDataCenter'
-        body = {'action': action,
-                'request': 'true',
-                'dataCenterId': datacenter.id,
-                'dataCenterName': name
-                }
+        action = datacenter.href
+        body = {
+            'name': name
+        }
 
-        self.connection.request(action=action,
-                                data=body,
-                                method='POST').object
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type':
+                'application/json'
+            },
+            data=body,
+            method='PATCH',
+            with_full_url=True
+        )
 
-        return True
+        return self._to_datacenter(response.object, response.headers)
+
+    """
+    Image Extension Functions
+    """
 
-    def ex_clear_datacenter(self, datacenter):
+    def ex_describe_image(self, ex_href=None, ex_image_id=None):
         """
-        Clear a datacenter.
+        Describe a ProfitBricks image
 
-        This removes all objects in a DC.
+        :param      ex_href: The href for the image you are describing
+        :type       ex_href: ``str``
 
-        :param datacenter: The DC you're clearing.
-        :type datacenter: :class:`Datacenter`
+        :param      ex_image_id: The ID for the image you are describing
+        :type       ex_image_id: ``str``
+
+        :return:    Instance of class ``Image``
+        :rtype:     :class:`Image`
+        """
+
+        use_full_url = True
+
+        if ex_href is None:
+            if ex_image_id is None:
+                raise ValueError(
+                    'The image ID is required.'
+                )
+            else:
+                use_full_url = False
+                ex_href = (
+                    'images/{image_id}'
+                ).format(
+                    image_id=ex_image_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            with_full_url=use_full_url
+        )
+
+        return self._to_image(response.object)
+
+    def ex_delete_image(self, image):
+        """
+        Delete a private image
+
+        :param  image: The private image you are deleting.
+        :type   image: :class:`NodeImage`
 
         :rtype:     : ``bool``
         """
-        action = 'clearDataCenter'
-        body = {'action': action,
-                'dataCenterId': datacenter.id
-                }
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=image.extra['href'],
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
-    '''
+    def ex_update_image(
+        self, image, name=None, description=None,
+        licence_type=None, cpu_hot_plug=None,
+        cpu_hot_unplug=None, ram_hot_plug=None,
+        ram_hot_unplug=None, nic_hot_plug=None,
+        nic_hot_unplug=None, disc_virtio_hot_plug=None,
+        disc_virtio_hot_unplug=None, disc_scsi_hot_plug=None,
+        disc_scsi_hot_unplug=None
+    ):
+        """
+        Update a private image
+
+        :param  image: The private image you are deleting.
+        :type   image: :class:`NodeImage`
+
+        :return:    Instance of class ``Image``
+        :rtype:     :class:`Image`
+        """
+        action = image.extra['href']
+        body = {}
+
+        if name is not None:
+            body['name'] = name
+
+        if description is not None:
+            body['description'] = description
+
+        if licence_type is not None:
+            body['licence_type'] = licence_type
+
+        if cpu_hot_plug is not None:
+            body['cpu_hot_plug'] = cpu_hot_plug
+
+        if cpu_hot_unplug is not None:
+            body['cpu_hot_unplug'] = cpu_hot_unplug
+
+        if ram_hot_plug is not None:
+            body['ram_hot_plug'] = ram_hot_plug
+
+        if ram_hot_unplug is not None:
+            body['ram_hot_unplug'] = ram_hot_unplug
+
+        if nic_hot_plug is not None:
+            body['nic_hot_plug'] = nic_hot_plug
+
+        if nic_hot_unplug is not None:
+            body['nic_hot_unplug'] = nic_hot_unplug
+
+        if disc_virtio_hot_plug is not None:
+            body['disc_virtio_hot_plug'] = disc_virtio_hot_plug
+
+        if disc_virtio_hot_unplug is not None:
+            body['disc_virtio_hot_unplug'] = disc_virtio_hot_unplug
+
+        if disc_scsi_hot_plug is not None:
+            body['disc_scsi_hot_plug'] = disc_scsi_hot_plug
+
+        if disc_scsi_hot_unplug is not None:
+            body['disc_scsi_hot_unplug'] = disc_scsi_hot_unplug
+
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-type':
+                'application/json'
+            },
+            data=body,
+            method='PATCH',
+            with_full_url=True
+        )
+
+        return self._to_image(response.object, response.headers)
+
+    """
+    Location Extension Functions
+    """
+
+    def ex_describe_location(self, ex_href=None, ex_location_id=None):
+        """
+        Fetch details for a ProfitBricks location.
+
+        :param      ex_href: The href for the location
+                            you are describing.
+        :type       ex_href: ``str``
+
+        :param      ex_location_id: The id for the location you are
+                        describing ('de/fra', 'de/fkb', 'us/las')
+        :type       ex_location_id: ``str``
+
+        :return:    Instance of class ``NodeLocation``
+        :rtype:     :class:`NodeLocation`
+        """
+
+        use_full_url = True
+
+        if ex_href is None:
+            if ex_location_id is None:
+                raise ValueError(
+                    'The loctation ID is required.'
+                )
+            else:
+                use_full_url = False
+                ex_href = (
+                    'locations/{location_id}'
+                ).format(
+                    location_id=ex_location_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            with_full_url=use_full_url
+        )
+
+        return self._to_location(response.object)
+
+    """
     Network Interface Extension Functions
-    '''
+    """
 
     def ex_list_network_interfaces(self):
         """
-        Lists all network interfaces.
+        Fetch a list of all network interfaces from all data centers.
 
         :return:    ``list`` of class ``ProfitBricksNetworkInterface``
-        :rtype:     :class:`ProfitBricksNetworkInterface`
+        :rtype:     `list`
         """
-        action = 'getAllNic'
-        body = {'action': action}
+        nodes = self.list_nodes()
+        nics = list()
 
-        return self._to_interfaces(
-            self.connection.request(action=action,
-                                    data=body,
-                                    method='POST').object)
+        for node in nodes:
+            action = node.extra['entities']['nics']['href']
+            nics += self._to_interfaces(
+                self.connection.request(
+                    action=action,
+                    params={'depth': 1},
+                    method='GET',
+                    with_full_url=True
+                ).object)
 
-    def ex_describe_network_interface(self, network_interface):
+        return nics
+
+    def ex_describe_network_interface(
+        self,
+        ex_href=None,
+        ex_datacenter_id=None,
+        ex_server_id=None,
+        ex_nic_id=None
+    ):
         """
-        Describes a network interface.
+        Fetch information on a network interface.
 
-        :param network_interface: The NIC you wish to describe.
-        :type network_interface: :class:`ProfitBricksNetworkInterface`
+        :param  ex_href: The href of the NIC you wish to describe.
+        :type   ex_href: ``str``
+
+        :param  ex_datacenter_id: The ID of parent data center
+                            of the NIC you wish to describe.
+        :type   ex_datacenter_id: ``str``
+
+        :param  ex_server_id: The server the NIC is connected to.
+        :type   ex_server_id: ``str``
+
+        :param  ex_nic_id: The ID of the NIC
+        :type   ex_nic_id: ``str``
 
         :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])
+        use_full_url = True
+
+        if ex_href is None:
+            if (
+                ex_datacenter_id is None or
+                ex_server_id is None or
+                ex_nic_id is None
+            ):
+                raise ValueError(
+                    (
+                        'IDs are required for the data center',
+                        'server and network interface.'
+                    )
+                )
+            else:
+                use_full_url = False
+                ex_href = (
+                    'datacenters/{datacenter_id}'
+                    '/servers/{server_id}'
+                    '/nics/{nic_id}'
+                ).format(
+                    datacenter_id=ex_datacenter_id,
+                    server_id=ex_server_id,
+                    nic_id=ex_nic_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            with_full_url=use_full_url
+        )
+
+        return self._to_interface(response.object)
 
     def ex_create_network_interface(self, node,
-                                    lan_id=None, ip=None, nic_name=None,
+                                    lan_id=None, ips=None, nic_name=None,
                                     dhcp_active=True):
         """
         Creates a network interface.
@@ -1038,8 +1880,8 @@ class ProfitBricksNodeDriver(NodeDriver):
         :param lan_id: The ID for the LAN.
         :type lan_id: : ``int``
 
-        :param ip: The IP address for the NIC.
-        :type ip: ``str``
+        :param ips: The IP addresses for the NIC.
+        :type ips: ``list``
 
         :param nic_name: The name of the NIC, e.g. PUBLIC.
         :type nic_name: ``str``
@@ -1050,72 +1892,94 @@ class ProfitBricksNodeDriver(NodeDriver):
         :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)
+        if lan_id is not None:
+            lan_id = str(lan_id)
+
         else:
-            body['lanId'] = str(1)
+            lan_id = str(1)
+
+        action = node.extra['href'] + '/nics'
+        body = {
+            'properties': {
+                'lan': lan_id,
+                'dhcp': dhcp_active
+            }
+        }
 
-        if ip:
-            body['ip'] = ip
+        if ips is not None:
+            body['properties']['ips'] = ips
 
-        if nic_name:
-            body['nicName'] = nic_name
+        if nic_name is not None:
+            body['properties']['name'] = nic_name
 
-        data = self.connection.request(action=action,
-                                       data=body,
-                                       method='POST').object
-        interfaces = self._to_interfaces(data)
-        return interfaces[0]
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'application/json'
+            },
+            data=body,
+            method='POST',
+            with_full_url=True
+        )
+
+        return self._to_interface(response.object, response.headers)
 
     def ex_update_network_interface(self, network_interface, name=None,
-                                    lan_id=None, ip=None,
+                                    lan_id=None, ips=None,
                                     dhcp_active=None):
         """
         Updates a network interface.
 
-        :param lan_id: The ID for the LAN.
-        :type lan_id: : ``int``
+        :param  network_interface: The network interface being updated.
+        :type   network_interface: :class:`ProfitBricksNetworkInterface`
 
-        :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 name: The name of the NIC, e.g. PUBLIC.
-        :type name: ``str``
+        :param  lan_id: The ID for the LAN.
+        :type   lan_id: : ``int``
 
-        :param dhcp_active: Set to false to disable.
-        :type dhcp_active: ``bool``
+        :param  ips: The IP addresses for the NIC as a list.
+        :type   ips: ``list``
 
-        :rtype:     : ``bool``
-        """
-        action = 'updateNic'
-        body = {'action': action,
-                'request': 'true',
-                'nicId': network_interface.id
-                }
+        :param  dhcp_active: Set to false to disable.
+        :type   dhcp_active: ``bool``
 
-        if name:
-            body['nicName'] = name
+        :return:    Instance of class ``ProfitBricksNetworkInterface``
+        :rtype:     :class:`ProfitBricksNetworkInterface`
+        """
 
         if lan_id:
-            body['lanId'] = str(lan_id)
+            lan_id = str(lan_id)
 
-        if ip:
-            body['ip'] = ip
+        action = network_interface.href
+        body = {}
+
+        if name is not None:
+            body['name'] = name
+
+        if lan_id is not None:
+            body['lan'] = str(lan_id)
+
+        if ips is not None:
+            body['ips'] = ips
 
         if dhcp_active is not None:
-            body['dhcpActive'] = str(dhcp_active).lower()
+            body['dhcp'] = dhcp_active
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type':
+                'application/json'
+            },
+            data=body,
+            method='PATCH',
+            with_full_url=True
+        )
 
-        return True
+        return self._to_interface(response.object, response.headers)
 
     def ex_destroy_network_interface(self, network_interface):
         """
@@ -1127,378 +1991,1981 @@ class ProfitBricksNodeDriver(NodeDriver):
         :rtype:     : ``bool``
         """
 
-        action = 'deleteNic'
-        body = {'action': action,
-                'nicId': network_interface.id}
+        action = network_interface.href
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        self.connection.request(
+            action=action,
+            method='DELETE',
+            with_full_url=True
+        )
 
         return True
 
-    def ex_set_inet_access(self, datacenter,
-                           network_interface, internet_access=True):
+    def ex_set_inet_access(self, network_interface, internet_access=True):
+        """
+        Add/remove public internet access to an interface.
 
-        action = 'setInternetAccess'
+        :param network_interface: The NIC you wish to update.
+        :type network_interface: :class:`ProfitBricksNetworkInterface`
 
-        body = {'action': action,
-                'dataCenterId': datacenter.id,
-                'lanId': network_interface.extra['lan_id'],
-                'internetAccess': str(internet_access).lower()
-                }
+        :return:    Instance of class ``ProfitBricksNetworkInterface``
+        :rtype:     :class:`ProfitBricksNetworkInterface`
+        """
 
-        self.connection.request(action=action,
-                                data=body, method='POST').object
+        action = network_interface.href
+        body = {
+            'nat': internet_access
+        }
 
-        return True
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type':
+                'application/json'
+            },
+            data=body,
+            method='PATCH',
+            with_full_url=True
+        )
+
+        return self._to_interface(response.object, response.headers)
 
     """
-    Private Functions
+    Firewall Rule Extension 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
+    def ex_list_firewall_rules(self, network_interface):
+        """
+        Fetch firewall rules for a network interface.
 
-        if ET.iselement(image.find('memoryHotpluggable')):
-            memory_hotpluggable = image.find('memoryHotpluggable').text
-        else:
-            memory_hotpluggable = None
+        :param network_interface: The network interface.
+        :type network_interface: :class:`ProfitBricksNetworkInterface`
 
-        if ET.iselement(image.find('location')):
-            if image.find('region'):
-                image_region = image.find('region').text
+        :return:    ``list`` of class ``ProfitBricksFirewallRule``
+        :rtype:     `list`
+        """
+        action = network_interface.href + '/firewallrules'
+        response = self.connection.request(
+            action=action,
+            method='GET',
+            params={'depth': 3},
+            with_full_url=True
+        )
+
+        return self._to_firewall_rules(response.object)
+
+    def ex_describe_firewall_rule(
+        self,
+        ex_href=None,
+        ex_datacenter_id=None,
+        ex_server_id=None,
+        ex_nic_id=None,
+        ex_firewall_rule_id=None
+    ):
+        """
+        Fetch data for a firewall rule.
+
+        :param href: The href of the firewall rule you wish to describe.
+        :type href: ``str``
+
+        :param  ex_datacenter_id: The ID of parent data center
+                            of the NIC you wish to describe.
+        :type   ex_datacenter_id: ``str``
+
+        :param  ex_server_id: The server the NIC is connected to.
+        :type   ex_server_id: ``str``
+
+        :param  ex_nic_id: The ID of the NIC.
+        :type   ex_nic_id: ``str``
+
+        :param  ex_firewall_rule_id: The ID of the firewall rule.
+        :type   ex_firewall_rule_id: ``str``
+
+        :return:    Instance class ``ProfitBricksFirewallRule``
+        :rtype:     :class:`ProfitBricksFirewallRule`
+        """
+
+        use_full_url = True
+
+        if ex_href is None:
+            if (
+                ex_datacenter_id is None or
+                ex_server_id is None or
+                ex_nic_id is None or
+                ex_firewall_rule_id is None
+            ):
+                raise ValueError(
+                    (
+                        'IDs are required for the data '
+                        'center, server, network interface',
+                        'and firewall rule.'
+                    )
+                )
             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})
+                use_full_url = False
+                ex_href = (
+                    'datacenters/{datacenter_id}'
+                    '/servers/{server_id}'
+                    '/nics/{nic_id}'
+                    '/firewallrules/{firewall_rule_id}'
+                ).format(
+                    datacenter_id=ex_datacenter_id,
+                    server_id=ex_server_id,
+                    nic_id=ex_nic_id,
+                    firewall_rule_id=ex_firewall_rule_id
+                )
+
+        response = self.connection.request(
+            action=ex_href,
+            method='GET',
+            with_full_url=use_full_url
+        )
+
+        return self._to_firewall_rule(response.object)
+
+    def ex_create_firewall_rule(self, network_interface, protocol,
+                                name=None, source_mac=None,
+                                source_ip=None, target_ip=None,
+                                port_range_start=None, port_range_end=None,
+                                icmp_type=None, icmp_code=None):
+        """
+        Create a firewall rule for a network interface.
+
+        :param  network_interface: The network interface to
+                        attach the firewall rule to.
+        :type:  network_interface: :class:`ProfitBricksNetworkInterface`
+
+        :param  protocol: The protocol for the rule (TCP, UDP, ICMP, ANY)
+        :type   protocol: ``str``
+
+        :param  name: The name for the firewall rule
+        :type   name: ``str``
+
+        :param  source_mac: Only traffic originating from the respective
+                            MAC address is allowed.
+                            Valid format: aa:bb:cc:dd:ee:ff.
+                            Value null allows all source MAC address.
+        :type   source_mac: ``str``
+
+        :param  source_ip: Only traffic originating from the respective IPv4
+                    address is allowed. Value null allows all source IPs.
+        :type   source_ip: ``str``
+
+        :param  target_ip: In case the target NIC has multiple IP addresses,
+                        only traffic directed to the respective IP address
+                        of the NIC is allowed.
+                        Value null allows all target IPs.
+        :type   target_ip: ``str``
+
+        :param  port_range_start: Defines the start range of the allowed port
+                        (from 1 to 65534) if protocol TCP or UDP is chosen.
+                        Leave portRangeStart and portRangeEnd value null
+                        to allow all ports.
+        type:   port_range_start: ``int``
+
+        :param  port_range_end: Defines the end range of the allowed port
+                        (from 1 to 65534) if protocol TCP or UDP is chosen.
+                        Leave portRangeStart and portRangeEnd value null
+                        to allow all ports.
+        type:   port_range_end: ``int``
+
+        :param  icmp_type: Defines the allowed type (from 0 to 254) if the
+                        protocol ICMP is chosen. Value null allows all types.
+        :type   icmp_type: ``int``
+
+        :param  icmp_code: Defines the allowed code (from 0 to 254) if
+                    protocol ICMP is chosen. Value null allows all codes.
+        :type   icmp_code: ``int``
+
+        :return:    Instance class ``ProfitBricksFirewallRule``
+        :rtype:     :class:`ProfitBricksFirewallRule`
+        """
+
+        action = network_interface.href + '/firewallrules'
+        body = {
+            'properties': {
+                'protocol': protocol
+            }
+        }
 
-    def _to_nodes(self, object):
-        return [self._to_node(n) for n in object.findall('.//return')]
+        if name is not None:
+            body['properties']['name'] = name
 
-    def _to_node(self, node):
-        """
-        Convert the request into a node Node
+        if source_mac is not None:
+            body['properties']['sourceMac'] = source_mac
+
+        if source_ip is not None:
+            body['properties']['sourceIp'] = source_ip
+
+        if target_ip is not None:
+            body['properties']['targetIp'] = target_ip
+
+        if port_range_start is not None:
+            body['properties']['portRangeStart'] = str(port_range_start)
+
+        if port_range_end is not None:
+            body['properties']['portRangeEnd'] = str(port_range_end)
+
+        if icmp_type is not None:
+            body['properties']['icmpType'] = str(icmp_type)
+
+        if icmp_code is not None:
+            body['properties']['icmpType'] = str(icmp_code)
+
+        response = self.connection.request(
+            action=action,
+            headers={
+                'Content-Type': 'ap

<TRUNCATED>

[2/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_volumes.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_volumes.xml b/libcloud/test/compute/fixtures/profitbricks/list_volumes.xml
deleted file mode 100644
index 5b73042..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/list_volumes.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
-   <S:Body>
-      <ns2:getAllStoragesResponse xmlns:ns2="http://ws.api.profitbricks.com/">
-         <return>
-            <dataCenterId>06eac419-c2b3-4761-aeb9-10efdd2cf292</dataCenterId>
-            <dataCenterVersion>2</dataCenterVersion>
-            <storageId>453582cf-8d54-4ec8-bc0b-f9962f7fd232</storageId>
-            <size>50</size>
-            <storageName>storage001</storageName>
-            <mountImage>
-               <imageId>d2f627c4-0289-11e4-9f63-52540066fee9</imageId>
-               <imageName>CentOS-6-server-2014-07-01</imageName>
-            </mountImage>
-            <serverIds>ebee7d83-912b-42f1-9b62-b953351a7e29</serverIds>
-            <provisioningState>AVAILABLE</provisioningState>
-            <creationTime>2014-07-15T03:19:38.252Z</creationTime>
-            <lastModificationTime>2014-07-15T03:28:58.724Z</lastModificationTime>
-         </return>
-         <return>
-            <dataCenterId>06eac419-c2b3-4761-aeb9-10efdd2cf292</dataCenterId>
-            <dataCenterVersion>2</dataCenterVersion>
-            <storageId>4e547123-897b-4520-a74e-c4ae2ff62f92</storageId>
-            <size>50</size>
-            <storageName>storage002</storageName>
-            <mountImage>
-               <imageId>d2f627c4-0289-11e4-9f63-52540066fee9</imageId>
-               <imageName>CentOS-6-server-2014-07-01</imageName>
-            </mountImage>
-            <serverIds>86413124-8dd3-4708-8475-9b4e7d059401</serverIds>
-            <provisioningState>AVAILABLE</provisioningState>
-            <creationTime>2014-07-15T03:19:38.252Z</creationTime>
-            <lastModificationTime>2014-07-15T03:28:58.724Z</lastModificationTime>
-         </return>
-         <return>
-            <dataCenterId>06eac419-c2b3-4761-aeb9-10efdd2cf292</dataCenterId>
-            <dataCenterVersion>2</dataCenterVersion>
-            <storageId>0c893ea8-6bd7-483f-9d72-5a2fc4edff83</storageId>
-            <size>50</size>
-            <storageName>storage003</storageName>
-            <mountImage>
-               <imageId>d2f627c4-0289-11e4-9f63-52540066fee9</imageId>
-               <imageName>CentOS-6-server-2014-07-01</imageName>
-            </mountImage>
-            <serverIds>ebee7d83-912b-42f1-9b62-b953351a7e29</serverIds>
-            <provisioningState>AVAILABLE</provisioningState>
-            <creationTime>2014-07-15T03:28:58.724Z</creationTime>
-            <lastModificationTime>2014-07-15T03:28:58.724Z</lastModificationTime>
-         </return>
-         <return>
-            <dataCenterId>06eac419-c2b3-4761-aeb9-10efdd2cf292</dataCenterId>
-            <dataCenterVersion>2</dataCenterVersion>
-            <storageId>6584f97e-90f3-4664-8d5b-8ff4539bf800</storageId>
-            <size>50</size>
-            <storageName>storage004</storageName>
-            <mountImage>
-               <imageId>10033683-01e2-11e4-9f63-52540066fee9</imageId>
-               <imageName>Ubuntu-13.10-server-2014-07-01</imageName>
-            </mountImage>
-            <provisioningState>AVAILABLE</provisioningState>
-            <creationTime>2014-07-15T03:28:58.724Z</creationTime>
-            <lastModificationTime>2014-07-15T03:28:58.724Z</lastModificationTime>
-         </return>
-      </ns2:getAllStoragesResponse>
-   </S:Body>
-</S:Envelope>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/reboot_node.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/reboot_node.xml b/libcloud/test/compute/fixtures/profitbricks/reboot_node.xml
deleted file mode 100644
index afb9e37..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/reboot_node.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
-   <S:Body>
-      <ns2:resetServerResponse xmlns:ns2="http://ws.api.profitbricks.com/">
-         <return>
-            <requestId>3492524</requestId>
-         </return>
-      </ns2:resetServerResponse>
-   </S:Body>
-</S:Envelope>
\ No newline at end of file


[3/9] libcloud git commit: [LIBCLOUD-873] Updated ProfitBricks Compute Driver (REST api v3)

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_lans.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_lans.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_lans.json
new file mode 100644
index 0000000..ede4187
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_lans.json
@@ -0,0 +1,157 @@
+{
+    "id": "dc-1/lans",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/lans",
+    "items": [
+        {
+            "id": "1",
+            "type": "lan",
+            "href": "/cloudapi/v3/datacenters/dc-1/lans/1",
+            "metadata": {
+                "createdDate": "2016-10-24T08:03:22Z",
+                "createdBy": "test@test.te",
+                "etag": "1c30221454228d239f0610b6eb3f41d7",
+                "lastModifiedDate": "2016-10-24T08:03:22Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Switch for LAN 1",
+                "public": false
+            },
+            "entities": {
+                "nics": {
+                    "id": "1/nics",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/lans/1/nics",
+                    "items": [
+                        {
+                            "id": "dc5e1c66-7280-4a5c-8e13-51ce030e0980",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/d37abf6b-0980-4bf8-813b-b69863cf7b9e/nics/dc5e1c66-7280-4a5c-8e13-51ce030e0980",
+                            "metadata": {
+                                "createdDate": "2016-10-21T13:00:02Z",
+                                "createdBy": "test@test.te",
+                                "etag": "d8177b9c38b0366d26c28df0066ade9e",
+                                "lastModifiedDate": "2016-10-24T08:03:22Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Three",
+                                "mac": "02:01:49:87:3e:5f",
+                                "ips": [
+                                    "10.15.104.14"
+                                ],
+                                "dhcp": true,
+                                "lan": 1,
+                                "firewallActive": true,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "dc5e1c66-7280-4a5c-8e13-51ce030e0980/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/d37abf6b-0980-4bf8-813b-b69863cf7b9e/nics/dc5e1c66-7280-4a5c-8e13-51ce030e0980/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "912324a6-c057-445d-84dd-8fea82dfa719",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/811ab72b-f7f3-427b-8220-f031eae34f63/nics/912324a6-c057-445d-84dd-8fea82dfa719",
+                            "metadata": {
+                                "createdDate": "2016-10-21T13:00:02Z",
+                                "createdBy": "test@test.te",
+                                "etag": "d8177b9c38b0366d26c28df0066ade9e",
+                                "lastModifiedDate": "2016-10-24T08:03:22Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Two",
+                                "mac": "02:01:af:48:34:06",
+                                "ips": [
+                                    "10.15.104.13"
+                                ],
+                                "dhcp": true,
+                                "lan": 1,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "912324a6-c057-445d-84dd-8fea82dfa719/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/811ab72b-f7f3-427b-8220-f031eae34f63/nics/912324a6-c057-445d-84dd-8fea82dfa719/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "8d9fb87c-79f7-4c3c-8f7b-e2050a881b16",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/b1a64861-5819-498a-899a-a57126050952/nics/8d9fb87c-79f7-4c3c-8f7b-e2050a881b16",
+                            "metadata": {
+                                "createdDate": "2016-10-21T13:00:02Z",
+                                "createdBy": "test@test.te",
+                                "etag": "d8177b9c38b0366d26c28df0066ade9e",
+                                "lastModifiedDate": "2016-10-24T08:03:22Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Four",
+                                "mac": "02:01:7c:7b:0b:5a",
+                                "ips": [
+                                    "10.15.104.12"
+                                ],
+                                "dhcp": true,
+                                "lan": 1,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "8d9fb87c-79f7-4c3c-8f7b-e2050a881b16/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/b1a64861-5819-498a-899a-a57126050952/nics/8d9fb87c-79f7-4c3c-8f7b-e2050a881b16/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "76d7965d-19e5-491f-8b2f-1c4a3ef127b5",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-1/servers/77ef2301-b4df-46aa-8544-2dae76c9d7b5/nics/76d7965d-19e5-491f-8b2f-1c4a3ef127b5",
+                            "metadata": {
+                                "createdDate": "2016-10-21T13:00:02Z",
+                                "createdBy": "test@test.te",
+                                "etag": "eb2031a5e259fcb4f714646aca0282c6",
+                                "lastModifiedDate": "2016-10-24T08:03:22Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": "Five",
+                                "mac": "02:01:bb:ad:7d:58",
+                                "ips": [
+                                    "10.15.104.11"
+                                ],
+                                "dhcp": true,
+                                "lan": 1,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "76d7965d-19e5-491f-8b2f-1c4a3ef127b5/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-1/servers/77ef2301-b4df-46aa-8544-2dae76c9d7b5/nics/76d7965d-19e5-491f-8b2f-1c4a3ef127b5/firewallrules"
+                                }
+                            }
+                        }
+                    ]
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balanced_nics.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balanced_nics.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balanced_nics.json
new file mode 100644
index 0000000..bdd7ec3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balanced_nics.json
@@ -0,0 +1,69 @@
+{
+    "id": "s-3/nics",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics",
+    "items": [
+        {
+            "id": "nic-1",
+            "type": "nic",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1",
+            "metadata": {
+                "createdDate": "2016-10-17T15:46:38Z",
+                "createdBy": "test@test.te",
+                "etag": "dbd8216137cf0ec9951170f93fa8fa53",
+                "lastModifiedDate": "2016-10-17T18:19:43Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test network interface",
+                "mac": "02:01:0b:9d:4d:ce",
+                "ips": [
+                    "10.15.124.11"
+                ],
+                "dhcp": false,
+                "lan": 2,
+                "firewallActive": true,
+                "nat": false
+            },
+            "entities": {
+                "firewallrules": {
+                    "id": "nic-1/firewallrules",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1/firewallrules"
+                }
+            }
+        },
+        {
+            "id": "8f7ea845-cf40-49c8-9e93-68366f31d605",
+            "type": "nic",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/8f7ea845-cf40-49c8-9e93-68366f31d605",
+            "metadata": {
+                "createdDate": "2016-10-17T16:46:38Z",
+                "createdBy": "test@test.te",
+                "etag": "dbd8216137cf0ec9951170f93fa8fa54",
+                "lastModifiedDate": "2016-10-17T19:19:43Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Another test network interface",
+                "mac": "02:01:0b:9d:4d:dd",
+                "ips": [
+                    "10.15.124.12"
+                ],
+                "dhcp": false,
+                "lan": 2,
+                "firewallActive": true,
+                "nat": false
+            },
+            "entities": {
+                "firewallrules": {
+                    "id": "8f7ea845-cf40-49c8-9e93-68366f31d605/firewallrules",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1/firewallrules"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balancers.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balancers.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balancers.json
new file mode 100644
index 0000000..ffb3ef0
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_load_balancers.json
@@ -0,0 +1,216 @@
+{
+    "id": "dc-2/loadbalancers",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers",
+    "items": [
+        {
+            "id": "bal-1",
+            "type": "loadbalancer",
+            "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/bal-1",
+            "metadata": {
+                "createdDate": "2016-10-26T13:02:33Z",
+                "createdBy": "test@test.te",
+                "etag": "71e8df57a58615b9e15400ede4138b41",
+                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test One",
+                "ip": "111.112.113.114",
+                "dhcp": true
+            },
+            "entities": {
+                "balancednics": {
+                    "id": "bal-1/balancednics",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/bal-1/balancednics",
+                    "items": [
+                        {
+                            "id": "68e3bd55-55a1-4fa0-8903-8c3cf23ee30a",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-2/servers/92445f57-5378-4a5b-8b53-f0f36fb8e6ad/nics/68e3bd55-55a1-4fa0-8903-8c3cf23ee30a",
+                            "metadata": {
+                                "createdDate": "2016-10-26T13:02:33Z",
+                                "createdBy": "test@test.te",
+                                "etag": "20e915cf08106b7576f6b25b5c0a2bd6",
+                                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": null,
+                                "mac": "02:01:33:58:8d:e1",
+                                "ips": [
+                                    "162.254.25.6"
+                                ],
+                                "dhcp": true,
+                                "lan": 3,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "68e3bd55-55a1-4fa0-8903-8c3cf23ee30a/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-2/servers/92445f57-5378-4a5b-8b53-f0f36fb8e6ad/nics/68e3bd55-55a1-4fa0-8903-8c3cf23ee30a/firewallrules"
+                                }
+                            }
+                        }
+                    ]
+                }
+            }
+        },
+        {
+            "id": "24d24a20-1161-4870-8b49-434622a18875",
+            "type": "loadbalancer",
+            "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/24d24a20-1161-4870-8b49-434622a18875",
+            "metadata": {
+                "createdDate": "2016-10-26T13:02:33Z",
+                "createdBy": "test@test.te",
+                "etag": "71e8df57a58615b9e15400ede4138b41",
+                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test Two",
+                "ip": "162.254.25.225",
+                "dhcp": true
+            },
+            "entities": {
+                "balancednics": {
+                    "id": "24d24a20-1161-4870-8b49-434622a18875/balancednics",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-2/loadbalancers/24d24a20-1161-4870-8b49-434622a18875/balancednics",
+                    "items": [
+                        {
+                            "id": "0485e083-3461-447a-8c5a-392be3c76473",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-2/servers/7571b2d9-312a-45be-8d68-58c269c3911c/nics/0485e083-3461-447a-8c5a-392be3c76473",
+                            "metadata": {
+                                "createdDate": "2016-10-25T08:49:48Z",
+                                "createdBy": "test@test.te",
+                                "etag": "20e915cf08106b7576f6b25b5c0a2bd6",
+                                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": null,
+                                "mac": "02:01:6f:92:d0:63",
+                                "ips": [
+                                    "162.254.25.225"
+                                ],
+                                "dhcp": true,
+                                "lan": 5,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "0485e083-3461-447a-8c5a-392be3c76473/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-2/servers/7571b2d9-312a-45be-8d68-58c269c3911c/nics/0485e083-3461-447a-8c5a-392be3c76473/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "2e9c54f4-85c0-4d10-8369-cf5e3a6e7b68",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-2/servers/ff3b523c-21bd-453d-80a3-c2bcdae1f509/nics/2e9c54f4-85c0-4d10-8369-cf5e3a6e7b68",
+                            "metadata": {
+                                "createdDate": "2016-10-25T14:01:03Z",
+                                "createdBy": "test@test.te",
+                                "etag": "20e915cf08106b7576f6b25b5c0a2bd6",
+                                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": null,
+                                "mac": "02:01:ce:53:f1:1a",
+                                "ips": [
+                                    "162.254.25.225"
+                                ],
+                                "dhcp": true,
+                                "lan": 5,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "2e9c54f4-85c0-4d10-8369-cf5e3a6e7b68/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-2/servers/ff3b523c-21bd-453d-80a3-c2bcdae1f509/nics/2e9c54f4-85c0-4d10-8369-cf5e3a6e7b68/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "707d7aa4-8311-4a61-82a4-a80333e9ecc2",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-2/servers/2e77a9cc-2338-43e6-84bf-e4c2ff9be265/nics/707d7aa4-8311-4a61-82a4-a80333e9ecc2",
+                            "metadata": {
+                                "createdDate": "2016-10-25T15:36:06Z",
+                                "createdBy": "test@test.te",
+                                "etag": "20e915cf08106b7576f6b25b5c0a2bd6",
+                                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": null,
+                                "mac": "02:01:8b:77:cd:b6",
+                                "ips": [
+                                    "162.254.25.225"
+                                ],
+                                "dhcp": true,
+                                "lan": 5,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "707d7aa4-8311-4a61-82a4-a80333e9ecc2/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-2/servers/2e77a9cc-2338-43e6-84bf-e4c2ff9be265/nics/707d7aa4-8311-4a61-82a4-a80333e9ecc2/firewallrules"
+                                }
+                            }
+                        },
+                        {
+                            "id": "710f6842-440d-4fdc-878e-0c329037d4a9",
+                            "type": "nic",
+                            "href": "/cloudapi/v3/datacenters/dc-2/servers/fc0f7e86-a7de-4cee-84b5-409cc8b89ad2/nics/710f6842-440d-4fdc-878e-0c329037d4a9",
+                            "metadata": {
+                                "createdDate": "2016-10-25T14:01:03Z",
+                                "createdBy": "test@test.te",
+                                "etag": "20e915cf08106b7576f6b25b5c0a2bd6",
+                                "lastModifiedDate": "2016-10-26T13:02:33Z",
+                                "lastModifiedBy": "test@test.te",
+                                "state": "AVAILABLE"
+                            },
+                            "properties": {
+                                "name": null,
+                                "mac": "02:01:00:65:da:a9",
+                                "ips": [
+                                    "162.254.25.225"
+                                ],
+                                "dhcp": true,
+                                "lan": 5,
+                                "firewallActive": false,
+                                "nat": false
+                            },
+                            "entities": {
+                                "firewallrules": {
+                                    "id": "710f6842-440d-4fdc-878e-0c329037d4a9/firewallrules",
+                                    "type": "collection",
+                                    "href": "/cloudapi/v3/datacenters/dc-2/servers/fc0f7e86-a7de-4cee-84b5-409cc8b89ad2/nics/710f6842-440d-4fdc-878e-0c329037d4a9/firewallrules"
+                                }
+                            }
+                        }
+                    ]
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.json b/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.json
new file mode 100644
index 0000000..bdd7ec3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.json
@@ -0,0 +1,69 @@
+{
+    "id": "s-3/nics",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics",
+    "items": [
+        {
+            "id": "nic-1",
+            "type": "nic",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1",
+            "metadata": {
+                "createdDate": "2016-10-17T15:46:38Z",
+                "createdBy": "test@test.te",
+                "etag": "dbd8216137cf0ec9951170f93fa8fa53",
+                "lastModifiedDate": "2016-10-17T18:19:43Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test network interface",
+                "mac": "02:01:0b:9d:4d:ce",
+                "ips": [
+                    "10.15.124.11"
+                ],
+                "dhcp": false,
+                "lan": 2,
+                "firewallActive": true,
+                "nat": false
+            },
+            "entities": {
+                "firewallrules": {
+                    "id": "nic-1/firewallrules",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1/firewallrules"
+                }
+            }
+        },
+        {
+            "id": "8f7ea845-cf40-49c8-9e93-68366f31d605",
+            "type": "nic",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/8f7ea845-cf40-49c8-9e93-68366f31d605",
+            "metadata": {
+                "createdDate": "2016-10-17T16:46:38Z",
+                "createdBy": "test@test.te",
+                "etag": "dbd8216137cf0ec9951170f93fa8fa54",
+                "lastModifiedDate": "2016-10-17T19:19:43Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Another test network interface",
+                "mac": "02:01:0b:9d:4d:dd",
+                "ips": [
+                    "10.15.124.12"
+                ],
+                "dhcp": false,
+                "lan": 2,
+                "firewallActive": true,
+                "nat": false
+            },
+            "entities": {
+                "firewallrules": {
+                    "id": "8f7ea845-cf40-49c8-9e93-68366f31d605/firewallrules",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1/firewallrules"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 7164f22..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_list_network_interfaces.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_rename_datacenter.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_rename_datacenter.json b/libcloud/test/compute/fixtures/profitbricks/ex_rename_datacenter.json
new file mode 100644
index 0000000..bfb2d5b
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_rename_datacenter.json
@@ -0,0 +1,46 @@
+{
+    "id": "dc-1",
+    "type": "datacenter",
+    "href": "/cloudapi/v3/datacenters/dc-1",
+    "metadata" : {
+        "createdDate": "2016-10-17T11:33:11Z",
+        "createdBy": "test@test.test",
+        "etag": "53b215b8ec0356a649955dab019845a4",
+        "lastModifiedDate": "2016-10-18T15:13:44Z",
+        "lastModifiedBy": "test@test.test",
+        "state" : "BUSY"
+    },
+    "properties" : {
+        "name": "Test Data Center",
+        "description": "This is a test data center.",
+        "location": "de/fkb",
+        "version": 35,
+        "features": [
+            "SSD",
+            "MULTIPLE_CPU"
+        ]
+    },
+    "entities" : {
+        "servers" : {
+            "id": "dc-1/servers",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers"
+        },
+        "volumes" : {
+            "id": "dc-1/volumes",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes"
+        },
+        "loadbalancers" : {
+            "id": "dc-1/loadbalancers",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/loadbalancers",
+            "items": []
+        },
+        "lans" : {
+            "id": "dc-1/lans",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/lans"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_set_inet_access.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_set_inet_access.json b/libcloud/test/compute/fixtures/profitbricks/ex_set_inet_access.json
new file mode 100644
index 0000000..badfd0a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_set_inet_access.json
@@ -0,0 +1,31 @@
+{
+    "id": "nic-2",
+    "type": "nic",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2",
+    "metadata": {
+        "createdDate": "2016-10-19T08:18:55Z",
+        "createdBy": "test@test.te",
+        "etag": "56f8d8bbdc84faad4188f647a49a565b",
+        "lastModifiedDate": "2016-10-19T09:44:59Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Updated from LibCloud",
+        "mac": "02:01:68:c1:e8:88",
+        "ips": [
+            "11.12.13.14"
+        ],
+        "dhcp": true,
+        "lan": 1,
+        "firewallActive": false,
+        "nat": false
+    },
+    "entities": {
+        "firewallrules": {
+            "id": "nic-2/firewallrules",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index f83d6a4..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_start_node.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index f83d6a4..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_stop_node.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?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/2569a5f2/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
deleted file mode 100644
index 270aa41..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_update_datacenter.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_firewall_rule.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_firewall_rule.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_firewall_rule.json
new file mode 100644
index 0000000..f6d13ef
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_firewall_rule.json
@@ -0,0 +1,25 @@
+{
+    "id": "fw2",
+    "type": "firewall-rule",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-2/firewallrules/fw2",
+    "metadata": {
+        "createdDate": "2016-10-19T09:55:10Z",
+        "createdBy": "test@test.te",
+        "etag": "00bb5b86562db1ed19ca38697e485160",
+        "lastModifiedDate": "2016-10-19T09:55:10Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "HTTPs (SSL)",
+        "protocol": "TCP",
+        "sourceMac": null,
+        "sourceIp": null,
+        "targetIp": null,
+        "icmpCode": null,
+        "icmpType": null,
+        "portRangeStart": 443,
+        "portRangeEnd": 443
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_image.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_image.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_image.json
new file mode 100644
index 0000000..32db4ce
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_image.json
@@ -0,0 +1,32 @@
+{
+    "id": "img-2",
+    "type": "image",
+    "href": "/cloudapi/v3/images/img-2",
+    "metadata": {
+        "createdDate": "2015-10-09T12:06:34Z",
+        "createdBy": "test@test.te",
+        "etag": "bbf76112358af2fc5dd1bf21de8988db",
+        "lastModifiedDate": "2016-11-11T15:23:20Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "my-updated-image.img",
+        "description": null,
+        "location": "de/fkb",
+        "size": 2,
+        "cpuHotPlug": false,
+        "cpuHotUnplug": false,
+        "ramHotPlug": false,
+        "ramHotUnplug": false,
+        "nicHotPlug": false,
+        "nicHotUnplug": false,
+        "discVirtioHotPlug": false,
+        "discVirtioHotUnplug": false,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "licenceType": "UNKNOWN",
+        "imageType": "HDD",
+        "public": false
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_lan.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_lan.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_lan.json
new file mode 100644
index 0000000..27b841d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_lan.json
@@ -0,0 +1,24 @@
+{
+    "id" : "10",
+    "type" : "lan",
+    "href" : "/cloudapi/v3/datacenters/dc-1/lans/10",
+    "metadata" : {
+        "createdDate": "2016-10-17T11:33:11Z",
+        "createdBy": "test@test.te",
+        "etag": "53b215b8ec0356a649955dab019845a4",
+        "lastModifiedDate": "2016-10-18T15:13:44Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties" : {
+        "name" : "Test Updated Lan",
+        "public" : true
+    },
+    "entities": {
+        "nics": {
+            "id": "10/nics",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/lans/10/nics"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_load_balancer.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_load_balancer.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_load_balancer.json
new file mode 100644
index 0000000..0705e68
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_load_balancer.json
@@ -0,0 +1,18 @@
+{
+    "id": "bal-1",
+    "type": "loadbalancer",
+    "href": "/cloudapi/v3/datacenters/dc-1/loadbalancers/bal-1",
+    "metadata": {
+        "createdDate": "2019-10-26T13:02:33Z",
+        "createdBy": "test@test.te",
+        "etag": "71e8df57a58615b9e15400ede4138b41",
+        "lastModifiedDate": "2019-10-26T13:02:33Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Updated Load Balancer",
+        "ip": "123.124.125.126",
+        "dhcp": false
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.json
new file mode 100644
index 0000000..d0fb880
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.json
@@ -0,0 +1,31 @@
+{
+    "id": "nic-1",
+    "type": "nic",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1",
+    "metadata": {
+        "createdDate": "2016-10-17T15:46:38Z",
+        "createdBy": "test@test.te",
+        "etag": "23dd052b608b59be38cef62765af7039",
+        "lastModifiedDate": "2016-10-19T09:29:00Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "BUSY"
+    },
+    "properties": {
+        "name": "Updated from LibCloud",
+        "mac": "02:01:0b:9d:4d:ce",
+        "ips": [
+            "10.15.124.11"
+        ],
+        "dhcp": true,
+        "lan": 1,
+        "firewallActive": true,
+        "nat": false
+    },
+    "entities": {
+        "firewallrules": {
+            "id": "nic-1/firewallrules",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/s-3/nics/nic-1/firewallrules"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index f9f8e0d..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_update_network_interface.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_node.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_node.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_node.json
new file mode 100644
index 0000000..6df459d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_node.json
@@ -0,0 +1,45 @@
+{
+    "id": "srv-1",
+    "type": "server",
+    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1",
+    "metadata" : {
+        "createdDate": "2016-10-18T07:28:05Z",
+        "createdBy": "test@test.test",
+        "etag": "e7cf186125f51f3d9511754a40dcd12c",
+        "lastModifiedDate": "2016-10-18T07:28:05Z",
+        "lastModifiedBy": "test@test.test",
+        "state" : "BUSY"
+    },
+    "properties" : {
+        "name" : "A test node",
+        "cores" : 1,
+        "ram" : 512,
+        "bootCdrom" : null,
+        "availabilityZone": "AUTO",
+        "vmState": "RUNNING",
+        "bootCdrom": null,
+        "bootVolume": {
+            "id": "bvol-1",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1"
+        },
+        "cpuFamily" : "AMD_OPTERON"
+    },
+    "entities" : {
+        "cdroms": {
+            "id": "srv-1/cdroms",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/cdroms"
+        },
+        "volumes": {
+            "id": "srv-1/volumes",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes"
+        },
+        "nics": {
+            "id": "srv-1/nics",
+            "type": "collection",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics"
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 03693a7..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_update_node.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_snapshot.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_snapshot.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_snapshot.json
new file mode 100644
index 0000000..f37024e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_snapshot.json
@@ -0,0 +1,30 @@
+{
+    "id": "sshot",
+    "type": "snapshot",
+    "href": "/cloudapi/v3/snapshots/sshot",
+    "metadata": {
+        "createdDate": "2016-10-26T11:38:45Z",
+        "createdBy": "test@test.te",
+        "etag": "01873262ac042b5f44ed33b4241225b4",
+        "lastModifiedDate": "2016-10-26T11:38:45Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Updated snapshot",
+        "description": "Updated snapshot",
+        "location": "us/las",
+        "size": 10,
+        "cpuHotPlug": true,
+        "cpuHotUnplug": true,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "licenceType": "LINUX"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.json b/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.json
new file mode 100644
index 0000000..d0eab6a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.json
@@ -0,0 +1,35 @@
+{
+    "id": "vol-2",
+    "type": "volume",
+    "href": "/cloudapi/v3/datacenters/dc-1/volumes/vol-2",
+    "metadata": {
+        "createdDate": "2016-10-17T13:13:36Z",
+        "createdBy": "test@test.te",
+        "etag": "c1800ce349033f9cd2c095ea1ea4976a",
+        "lastModifiedDate": "2016-10-17T13:47:52Z",
+        "lastModifiedBy": "test@test.te",
+        "state": "AVAILABLE"
+    },
+    "properties": {
+        "name": "Updated storage name",
+        "type": "HDD",
+        "size": 40,
+        "availabilityZone": "AUTO",
+        "image": "bvol-img",
+        "imagePassword": null,
+        "sshKeys": null,
+        "bus": "VIRTIO",
+        "licenceType": "LINUX",
+        "cpuHotPlug": true,
+        "cpuHotUnplug": false,
+        "ramHotPlug": true,
+        "ramHotUnplug": false,
+        "nicHotPlug": true,
+        "nicHotUnplug": true,
+        "discVirtioHotPlug": true,
+        "discVirtioHotUnplug": true,
+        "discScsiHotPlug": false,
+        "discScsiHotUnplug": false,
+        "deviceNumber": 3
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 03693a7..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/ex_update_volume.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?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/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_images.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_images.json b/libcloud/test/compute/fixtures/profitbricks/list_images.json
new file mode 100644
index 0000000..f7d718c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/list_images.json
@@ -0,0 +1,199 @@
+{
+    "id": "images",
+    "type": "collection",
+    "href": "/cloudapi/v3/images",
+    "items": [
+        {
+            "id": "img-2",
+            "type": "image",
+            "href": "/cloudapi/v3/images/img-2",
+            "metadata": {
+                "createdDate": "2016-06-02T11:33:49Z",
+                "createdBy": "System",
+                "etag": "9909709d99655c6f31aca789998d7d89",
+                "lastModifiedDate": "2016-06-02T11:33:49Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-One-CDROM",
+                "description": "",
+                "location": "us/las",
+                "size": 0.23,
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "LINUX",
+                "imageType": "CDROM",
+                "public": false
+            }
+        },
+        {
+            "id": "img-1",
+            "type": "image",
+            "href": "/cloudapi/v3/images/img-1",
+            "metadata": {
+                "createdDate": "2014-11-14T15:22:19Z",
+                "createdBy": "System",
+                "etag": "957e0eac7456fa7554e73bf0d18860eb",
+                "lastModifiedDate": "2014-11-14T15:22:19Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-Two-CDROM",
+                "description": "",
+                "location": "us/las",
+                "size": 4,
+                "cpuHotPlug": false,
+                "cpuHotUnplug": false,
+                "ramHotPlug": false,
+                "ramHotUnplug": false,
+                "nicHotPlug": false,
+                "nicHotUnplug": false,
+                "discVirtioHotPlug": false,
+                "discVirtioHotUnplug": false,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "OTHER",
+                "imageType": "CDROM",
+                "public": true
+            }
+        },
+        {
+            "id": "62c525d9-b2cf-11e5-afa0-52540066fee9",
+            "type": "image",
+            "href": "/cloudapi/v3/images/62c525d9-b2cf-11e5-afa0-52540066fee9",
+            "metadata": {
+                "createdDate": "2016-01-04T10:39:08Z",
+                "createdBy": "System",
+                "etag": "28cb3e31d2ef98d37b367fe15d40373e",
+                "lastModifiedDate": "2016-01-04T10:39:08Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-Three-CDROM",
+                "description": "",
+                "location": "de/fkb",
+                "size": 0.37,
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "LINUX",
+                "imageType": "CDROM",
+                "public": true
+            }
+        },
+        {
+            "id": "e2c323ba-3c6d-11e6-9336-52540005ab80",
+            "type": "image",
+            "href": "/cloudapi/v3/images/e2c323ba-3c6d-11e6-9336-52540005ab80",
+            "metadata": {
+                "createdDate": "2016-06-27T13:48:53Z",
+                "createdBy": "System",
+                "etag": "216e2beb5e9bb5f7c3233ca3d0c4e9b2",
+                "lastModifiedDate": "2016-06-27T13:48:53Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-Four-HDD",
+                "description": "",
+                "location": "de/fkb",
+                "size": 0.28,
+                "cpuHotPlug": false,
+                "cpuHotUnplug": false,
+                "ramHotPlug": false,
+                "ramHotUnplug": false,
+                "nicHotPlug": false,
+                "nicHotUnplug": false,
+                "discVirtioHotPlug": false,
+                "discVirtioHotUnplug": false,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "OTHER",
+                "imageType": "HDD",
+                "public": false
+            }
+        },
+        {
+            "id": "f1d2be4a-7937-11e4-8053-52540066fee9",
+            "type": "image",
+            "href": "/cloudapi/v3/images/f1d2be4a-7937-11e4-8053-52540066fee9",
+            "metadata": {
+                "createdDate": "2014-12-01T08:56:31Z",
+                "createdBy": "System",
+                "etag": "fd23753bfae52a11bbdfdd478296cb2a",
+                "lastModifiedDate": "2014-12-01T08:56:31Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-Two-HDD",
+                "description": "",
+                "location": "de/fkb",
+                "size": 0.45,
+                "cpuHotPlug": false,
+                "cpuHotUnplug": false,
+                "ramHotPlug": false,
+                "ramHotUnplug": false,
+                "nicHotPlug": false,
+                "nicHotUnplug": false,
+                "discVirtioHotPlug": false,
+                "discVirtioHotUnplug": false,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "LINUX",
+                "imageType": "HDD",
+                "public": true
+            }
+        },
+        {
+            "id": "dfa08a48-7937-11e4-8053-52540066fee9",
+            "type": "image",
+            "href": "/cloudapi/v3/images/dfa08a48-7937-11e4-8053-52540066fee9",
+            "metadata": {
+                "createdDate": "2014-12-01T08:56:00Z",
+                "createdBy": "System",
+                "etag": "66da22f2893f1de8945c27e11bbc7ebf",
+                "lastModifiedDate": "2014-12-01T08:56:00Z",
+                "lastModifiedBy": "System",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test-Image-Three-HDD",
+                "description": "",
+                "location": "de/fra",
+                "size": 0.08,
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "LINUX",
+                "imageType": "HDD",
+                "public": true
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/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
deleted file mode 100644
index 3c8ac7b..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/list_images.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?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

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_locations.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_locations.json b/libcloud/test/compute/fixtures/profitbricks/list_locations.json
new file mode 100644
index 0000000..7694c22
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/list_locations.json
@@ -0,0 +1,43 @@
+{
+    "id": "locations",
+    "type": "collection",
+    "href": "/cloudapi/v3/locations",
+    "items": [
+        {
+            "id": "de/fkb",
+            "type": "location",
+            "href": "/cloudapi/v3/locations/de/fkb",
+            "properties": {
+                "name": "karlsruhe",
+                "features": [
+                    "SSD",
+                    "MULTIPLE_CPU"
+                ]
+            }
+        },
+        {
+            "id": "de/fra",
+            "type": "location",
+            "href": "/cloudapi/v3/locations/de/fra",
+            "properties": {
+                "name": "frankfurt",
+                "features": [
+                    "SSD",
+                    "MULTIPLE_CPU"
+                ]
+            }
+        },
+        {
+            "id": "us/las",
+            "type": "location",
+            "href": "/cloudapi/v3/locations/us/las",
+            "properties": {
+                "name": "lasvegas",
+                "features": [
+                    "SSD",
+                    "MULTIPLE_CPU"
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_nodes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_nodes.json b/libcloud/test/compute/fixtures/profitbricks/list_nodes.json
new file mode 100644
index 0000000..1f30a8c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/list_nodes.json
@@ -0,0 +1,169 @@
+{
+    "id": "dc-1/servers",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/9e9cb896-e8e7-4f52-a808-ac808baac814/servers",
+    "items": [
+        {
+            "id": "srv-1",
+            "type": "server",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1",
+            "metadata": {
+                "createdDate": "2016-10-18T07:28:05Z",
+                "createdBy": "test@test.te",
+                "etag": "e7cf186125f51f3d9511754a40dcd12c",
+                "lastModifiedDate": "2016-10-18T07:28:05Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test Node.",
+                "cores": 2,
+                "ram": 4096,
+                "availabilityZone": "AUTO",
+                "vmState": "RUNNING",
+                "bootCdrom": null,
+                "bootVolume": {
+                    "id": "bvol-1",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+                    "metadata": {
+                        "createdDate": "2016-10-18T07:20:41Z",
+                        "createdBy": "matfin@stackpointcloud.com",
+                        "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                        "lastModifiedDate": "2016-10-18T07:20:41Z",
+                        "lastModifiedBy": "test@test.te",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Test Node Volume",
+                        "type": "HDD",
+                        "size": 10,
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 1
+                    }
+                },
+                "cpuFamily": "AMD_OPTERON"
+            },
+            "entities": {
+                "cdroms": {
+                    "id": "srv-1/cdroms",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/cdroms",
+                    "items": []
+                },
+                "volumes": {
+                    "id": "srv-1/volumes",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes",
+                    "items": [
+                        {
+                            "id": "bvol-1",
+                            "type": "volume",
+                            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1"
+                        }
+                    ]
+                },
+                "nics": {
+                    "id": "srv-1/nics",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics",
+                    "items": []
+                }
+            }
+        },
+        {
+            "id": "srv-1",
+            "type": "server",
+            "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1",
+            "metadata": {
+                "createdDate": "2016-10-18T07:28:05Z",
+                "createdBy": "test@test.te",
+                "etag": "e7cf186125f51f3d9511754a40dcd12c",
+                "lastModifiedDate": "2016-10-18T07:28:05Z",
+                "lastModifiedBy": "matfin@stackpointcloud.com",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test Node.",
+                "cores": 2,
+                "ram": 4096,
+                "availabilityZone": "AUTO",
+                "vmState": "RUNNING",
+                "bootCdrom": null,
+                "bootVolume": {
+                    "id": "bvol-1",
+                    "type": "volume",
+                    "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+                    "metadata": {
+                        "createdDate": "2016-10-18T07:20:41Z",
+                        "createdBy": "matfin@stackpointcloud.com",
+                        "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                        "lastModifiedDate": "2016-10-18T07:20:41Z",
+                        "lastModifiedBy": "test@test.te",
+                        "state": "AVAILABLE"
+                    },
+                    "properties": {
+                        "name": "Test Node Volume",
+                        "type": "HDD",
+                        "size": 10,
+                        "image": "bvol-img",
+                        "imagePassword": null,
+                        "bus": "VIRTIO",
+                        "licenceType": "LINUX",
+                        "cpuHotPlug": true,
+                        "cpuHotUnplug": false,
+                        "ramHotPlug": true,
+                        "ramHotUnplug": false,
+                        "nicHotPlug": true,
+                        "nicHotUnplug": true,
+                        "discVirtioHotPlug": true,
+                        "discVirtioHotUnplug": true,
+                        "discScsiHotPlug": false,
+                        "discScsiHotUnplug": false,
+                        "deviceNumber": 1
+                    }
+                },
+                "cpuFamily": "AMD_OPTERON"
+            },
+            "entities": {
+                "cdroms": {
+                    "id": "srv-1/cdroms",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/cdroms",
+                    "items": []
+                },
+                "volumes": {
+                    "id": "srv-1/volumes",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/volumes",
+                    "items": [
+                        {
+                            "id": "bvol-1",
+                            "type": "volume",
+                            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1"
+                        }
+                    ]
+                },
+                "nics": {
+                    "id": "srv-1/nics",
+                    "type": "collection",
+                    "href": "/cloudapi/v3/datacenters/dc-1/servers/srv-1/nics",
+                    "items": []
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_nodes.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_nodes.xml b/libcloud/test/compute/fixtures/profitbricks/list_nodes.xml
deleted file mode 100644
index c392d25..0000000
--- a/libcloud/test/compute/fixtures/profitbricks/list_nodes.xml
+++ /dev/null
@@ -1,172 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
-   <S:Body>
-      <ns2:getAllServersResponse xmlns:ns2="http://ws.api.profitbricks.com/">
-         <return>
-            <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-            <dataCenterVersion>5</dataCenterVersion>
-            <serverId>c8e57d7b-e731-46ad-a913-1828c0562246</serverId>
-            <serverName>server001</serverName>
-            <cores>1</cores>
-            <ram>1024</ram>
-            <internetAccess>true</internetAccess>
-            <ips>10.13.198.11</ips>
-            <ips>162.254.25.197</ips>
-            <ips>10.10.108.12</ips>
-            <connectedStorages>
-               <bootDevice>true</bootDevice>
-               <busType>VIRTIO</busType>
-               <deviceNumber>1</deviceNumber>
-               <size>50</size>
-               <storageId>b07d7c20-8cd4-4502-aab1-c0195b7f18a1</storageId>
-               <storageName>server001-storage001</storageName>
-            </connectedStorages>
-            <nics>
-               <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-               <dataCenterVersion>5</dataCenterVersion>
-               <nicId>7fb08916-eb64-40b8-a081-fafe0e374145</nicId>
-               <lanId>2</lanId>
-               <internetAccess>false</internetAccess>
-               <serverId>c8e57d7b-e731-46ad-a913-1828c0562246</serverId>
-               <ips>10.10.108.12</ips>
-               <macAddress>02:01:b9:a5:81:d9</macAddress>
-               <firewall>
-                  <active>false</active>
-                  <firewallId>27062b18-aab9-4046-9071-c375121fdcd4</firewallId>
-                  <nicId>7fb08916-eb64-40b8-a081-fafe0e374145</nicId>
-                  <provisioningState>AVAILABLE</provisioningState>
-               </firewall>
-               <dhcpActive>true</dhcpActive>
-               <provisioningState>AVAILABLE</provisioningState>
-            </nics>
-            <nics>
-               <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-               <dataCenterVersion>5</dataCenterVersion>
-               <nicId>3f980c78-89b7-4f65-8e5d-28abc2f158aa</nicId>
-               <lanId>3</lanId>
-               <internetAccess>false</internetAccess>
-               <serverId>c8e57d7b-e731-46ad-a913-1828c0562246</serverId>
-               <ips>10.13.198.11</ips>
-               <macAddress>02:01:7f:31:2f:71</macAddress>
-               <firewall>
-                  <active>false</active>
-                  <firewallId>b644fbfd-ff6f-4ba5-882c-d0478f327819</firewallId>
-                  <nicId>3f980c78-89b7-4f65-8e5d-28abc2f158aa</nicId>
-                  <provisioningState>AVAILABLE</provisioningState>
-               </firewall>
-               <dhcpActive>true</dhcpActive>
-               <provisioningState>AVAILABLE</provisioningState>
-            </nics>
-            <nics>
-               <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-               <dataCenterVersion>5</dataCenterVersion>
-               <nicId>8df3ec08-b6f7-4038-85eb-da6620d31aa5</nicId>
-               <lanId>1</lanId>
-               <internetAccess>true</internetAccess>
-               <serverId>c8e57d7b-e731-46ad-a913-1828c0562246</serverId>
-               <ips>162.254.25.197</ips>
-               <macAddress>02:01:1f:9c:f3:24</macAddress>
-               <firewall>
-                  <active>false</active>
-                  <firewallId>0bd04380-b4f3-4013-96a2-d71d134fd895</firewallId>
-                  <nicId>8df3ec08-b6f7-4038-85eb-da6620d31aa5</nicId>
-                  <provisioningState>AVAILABLE</provisioningState>
-               </firewall>
-               <dhcpActive>true</dhcpActive>
-               <gatewayIp>162.254.25.1</gatewayIp>
-               <provisioningState>AVAILABLE</provisioningState>
-            </nics>
-            <provisioningState>AVAILABLE</provisioningState>
-            <virtualMachineState>RUNNING</virtualMachineState>
-            <creationTime>2014-07-14T20:52:20.839Z</creationTime>
-            <lastModificationTime>2014-07-14T22:11:09.324Z</lastModificationTime>
-            <osType>LINUX</osType>
-            <availabilityZone>ZONE_1</availabilityZone>
-         </return>
-         <return>
-            <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-            <dataCenterVersion>5</dataCenterVersion>
-            <serverId>7080c05b-1a91-4661-a217-60d864acee44</serverId>
-            <serverName>server002</serverName>
-            <cores>1</cores>
-            <ram>1024</ram>
-            <internetAccess>false</internetAccess>
-            <ips>10.13.198.12</ips>
-            <ips>10.10.108.11</ips>
-            <connectedStorages>
-               <bootDevice>true</bootDevice>
-               <busType>VIRTIO</busType>
-               <deviceNumber>1</deviceNumber>
-               <size>50</size>
-               <storageId>b96f49f6-c1d3-4250-8135-35c17c827657</storageId>
-               <storageName>server002-storage001</storageName>
-            </connectedStorages>
-            <nics>
-               <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-               <dataCenterVersion>5</dataCenterVersion>
-               <nicId>f1e0a1c6-329b-4629-b95b-ba81a30a4d73</nicId>
-               <lanId>2</lanId>
-               <internetAccess>false</internetAccess>
-               <serverId>7080c05b-1a91-4661-a217-60d864acee44</serverId>
-               <ips>10.10.108.11</ips>
-               <macAddress>02:01:58:5e:9a:3c</macAddress>
-               <firewall>
-                  <active>false</active>
-                  <firewallId>263d5a2c-c95b-4903-b290-a33cb47616c4</firewallId>
-                  <nicId>f1e0a1c6-329b-4629-b95b-ba81a30a4d73</nicId>
-                  <provisioningState>AVAILABLE</provisioningState>
-               </firewall>
-               <dhcpActive>true</dhcpActive>
-               <provisioningState>AVAILABLE</provisioningState>
-            </nics>
-            <nics>
-               <dataCenterId>e1e8ec0d-b47f-4d39-a91b-6e885483c899</dataCenterId>
-               <dataCenterVersion>5</dataCenterVersion>
-               <nicId>847c50c7-d7dc-4fe6-8216-e05dc7ea7b18</nicId>
-               <lanId>3</lanId>
-               <internetAccess>false</internetAccess>
-               <serverId>7080c05b-1a91-4661-a217-60d864acee44</serverId>
-               <ips>10.13.198.12</ips>
-               <macAddress>02:01:1e:32:2f:40</macAddress>
-               <firewall>
-                  <active>false</active>
-                  <firewallId>35c42660-94d5-483d-aca7-8e6e97507508</firewallId>
-                  <nicId>847c50c7-d7dc-4fe6-8216-e05dc7ea7b18</nicId>
-                  <provisioningState>AVAILABLE</provisioningState>
-               </firewall>
-               <dhcpActive>true</dhcpActive>
-               <provisioningState>AVAILABLE</provisioningState>
-            </nics>
-            <provisioningState>AVAILABLE</provisioningState>
-            <virtualMachineState>RUNNING</virtualMachineState>
-            <creationTime>2014-07-14T21:40:12.265Z</creationTime>
-            <lastModificationTime>2014-07-14T22:11:09.324Z</lastModificationTime>
-            <osType>LINUX</osType>
-            <availabilityZone>AUTO</availabilityZone>
-         </return>
-         <return>
-            <dataCenterId>6571ecd4-8602-4692-ae14-2f85eedbc403</dataCenterId>
-            <dataCenterVersion>2</dataCenterVersion>
-            <serverId>c9b9b603-65a3-4f11-bd24-ff1b494a85e2</serverId>
-            <serverName>server001</serverName>
-            <cores>1</cores>
-            <ram>1024</ram>
-            <internetAccess>false</internetAccess>
-            <connectedStorages>
-               <bootDevice>true</bootDevice>
-               <busType>VIRTIO</busType>
-               <deviceNumber>1</deviceNumber>
-               <size>50</size>
-               <storageId>06dad54e-85b2-4146-ab15-ef55cb121921</storageId>
-               <storageName>Storage</storageName>
-            </connectedStorages>
-            <provisioningState>AVAILABLE</provisioningState>
-            <virtualMachineState>RUNNING</virtualMachineState>
-            <creationTime>2014-07-14T21:06:21.421Z</creationTime>
-            <lastModificationTime>2014-07-14T21:06:21.421Z</lastModificationTime>
-            <osType>LINUX</osType>
-            <availabilityZone>ZONE_2</availabilityZone>
-         </return>
-      </ns2:getAllServersResponse>
-   </S:Body>
-</S:Envelope>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_snapshots.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_snapshots.json b/libcloud/test/compute/fixtures/profitbricks/list_snapshots.json
new file mode 100644
index 0000000..615dcb4
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/list_snapshots.json
@@ -0,0 +1,37 @@
+{
+    "id": "snapshots",
+    "type": "collection",
+    "href": "/cloudapi/v3/snapshots",
+    "items": [
+        {
+            "id": "sshot",
+            "type": "snapshot",
+            "href": "/cloudapi/v3/snapshots/sshot",
+            "metadata": {
+                "createdDate": "2016-10-26T11:38:45Z",
+                "createdBy": "test@test.te",
+                "etag": "01873262ac042b5f44ed33b4241225b4",
+                "lastModifiedDate": "2016-10-26T11:38:45Z",
+                "lastModifiedBy": "test@test.te",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Balancer Testing 1 Storage-Snapshot-10/26/2016",
+                "description": "Created from \"Balancer Testing 1 Storage\" in Data Center \"Snapshot\"",
+                "location": "us/las",
+                "size": 10,
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "licenceType": "LINUX"
+            }
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2569a5f2/libcloud/test/compute/fixtures/profitbricks/list_volumes.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/profitbricks/list_volumes.json b/libcloud/test/compute/fixtures/profitbricks/list_volumes.json
new file mode 100644
index 0000000..6111ca1
--- /dev/null
+++ b/libcloud/test/compute/fixtures/profitbricks/list_volumes.json
@@ -0,0 +1,112 @@
+{
+    "id": "dc-1/volumes",
+    "type": "collection",
+    "href": "/cloudapi/v3/datacenters/dc-1/volumes",
+    "items": [
+        {
+            "id": "bvol-1",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/bvol-1",
+            "metadata": {
+                "createdDate": "2016-10-18T07:20:41Z",
+                "createdBy": "test@test.test",
+                "etag": "33f6b8d506e7ad756e8554b915f29c61",
+                "lastModifiedDate": "2016-10-18T07:20:41Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Test Volume",
+                "type": "HDD",
+                "size": 10,
+                "availabilityZone": "AUTO",
+                "image": "bvol-img",
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": "VIRTIO",
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 1
+            }
+        },
+        {
+            "id": "d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/d6688ced-700d-4c9c-a3a7-9f7170c5edc3",
+            "metadata": {
+                "createdDate": "2016-10-17T13:13:36Z",
+                "createdBy": "test@test.test",
+                "etag": "c1800ce349033f9cd2c095ea1ea4976a",
+                "lastModifiedDate": "2016-10-17T13:47:52Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Updated storage name",
+                "type": "HDD",
+                "size": 40,
+                "availabilityZone": "AUTO",
+                "image": "bvol-img",
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": null,
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": null
+            }
+        },
+        {
+            "id": "21d7e7de-5054-4041-b691-717aa8b3c799",
+            "type": "volume",
+            "href": "/cloudapi/v3/datacenters/dc-1/volumes/21d7e7de-5054-4041-b691-717aa8b3c799",
+            "metadata": {
+                "createdDate": "2016-10-17T11:33:20Z",
+                "createdBy": "test@test.test",
+                "etag": "a9d0b923527efae5e7071e9118e9eece",
+                "lastModifiedDate": "2016-10-17T11:33:20Z",
+                "lastModifiedBy": "test@test.test",
+                "state": "AVAILABLE"
+            },
+            "properties": {
+                "name": "Image and location and size. - volume",
+                "type": "HDD",
+                "size": 50,
+                "availabilityZone": "AUTO",
+                "image": "bvol-img",
+                "imagePassword": null,
+                "sshKeys": null,
+                "bus": "VIRTIO",
+                "licenceType": "LINUX",
+                "cpuHotPlug": true,
+                "cpuHotUnplug": false,
+                "ramHotPlug": true,
+                "ramHotUnplug": false,
+                "nicHotPlug": true,
+                "nicHotUnplug": true,
+                "discVirtioHotPlug": true,
+                "discVirtioHotUnplug": true,
+                "discScsiHotPlug": false,
+                "discScsiHotUnplug": false,
+                "deviceNumber": 1
+            }
+        }
+    ]
+}
\ No newline at end of file


[8/9] libcloud git commit: changes for #938

Posted by an...@apache.org.
changes for #938


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/48b6a6a9
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/48b6a6a9
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/48b6a6a9

Branch: refs/heads/trunk
Commit: 48b6a6a918ada3b5d884738ccea394c0e5630257
Parents: ba389bd
Author: Anthony Shaw <an...@apache.org>
Authored: Mon Nov 14 15:17:01 2016 +1100
Committer: Anthony Shaw <an...@apache.org>
Committed: Mon Nov 14 15:17:01 2016 +1100

----------------------------------------------------------------------
 CHANGES.rst | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/48b6a6a9/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 9b65bd1..a929e58 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,10 @@ Changes in current version of Apache Libcloud
 Compute
 ~~~~~~~
 
+- [profitbricks] changes to the ProfitBricks compute driver to drop support for the old SOAP api (now end of life) and provide support for v3 of the REST api.
+  (GITHUB-938)
+  [Matt Finucane]
+
 - [cloudsigma] Added Warsaw (waw) region
   (GITHUB-942)
   [Kamil Chmielewski]


[9/9] libcloud git commit: regenerate provider tables

Posted by an...@apache.org.
regenerate provider tables


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/df93d65f
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/df93d65f
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/df93d65f

Branch: refs/heads/trunk
Commit: df93d65f67bc2a0eb1381675496e9200ff312b3f
Parents: 48b6a6a
Author: Anthony Shaw <an...@apache.org>
Authored: Mon Nov 14 15:17:56 2016 +1100
Committer: Anthony Shaw <an...@apache.org>
Committed: Mon Nov 14 15:17:56 2016 +1100

----------------------------------------------------------------------
 docs/compute/_supported_methods_block_storage.rst | 2 +-
 docs/storage/_supported_methods_cdn.rst           | 2 ++
 docs/storage/_supported_methods_main.rst          | 2 ++
 docs/storage/_supported_providers.rst             | 2 ++
 4 files changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/df93d65f/docs/compute/_supported_methods_block_storage.rst
----------------------------------------------------------------------
diff --git a/docs/compute/_supported_methods_block_storage.rst b/docs/compute/_supported_methods_block_storage.rst
index 2543ade..0ceebc9 100644
--- a/docs/compute/_supported_methods_block_storage.rst
+++ b/docs/compute/_supported_methods_block_storage.rst
@@ -43,7 +43,7 @@ Provider                              list volumes create volume destroy volume
 `Outscale SAS`_                       yes          yes           yes            yes           yes           yes            yes            
 `Ovh`_                                yes          yes           yes            yes           yes           yes            yes            
 `Packet`_                             no           no            no             no            no            no             no             
-`ProfitBricks`_                       yes          yes           yes            yes           yes           no             no             
+`ProfitBricks`_                       yes          yes           yes            yes           yes           no             yes            
 `Rackspace Cloud (Next Gen)`_         yes          yes           yes            yes           yes           yes            yes            
 `Rackspace Cloud (First Gen)`_        yes          yes           yes            yes           yes           no             no             
 `RimuHosting`_                        no           no            no             no            no            no             no             

http://git-wip-us.apache.org/repos/asf/libcloud/blob/df93d65f/docs/storage/_supported_methods_cdn.rst
----------------------------------------------------------------------
diff --git a/docs/storage/_supported_methods_cdn.rst b/docs/storage/_supported_methods_cdn.rst
index db4ea3f..2a63fb9 100644
--- a/docs/storage/_supported_methods_cdn.rst
+++ b/docs/storage/_supported_methods_cdn.rst
@@ -18,6 +18,7 @@ Provider                      enable container cdn enable object cdn get contain
 `Amazon S3 (ap-northeast-1)`_ no                   no                no                    no                
 `Amazon S3 (ap-northeast-2)`_ no                   no                no                    no                
 `Amazon S3 (ap-southeast-1)`_ no                   no                no                    no                
+`Amazon S3 (ap-southeast-2)`_ no                   no                no                    no                
 `Amazon S3 (cn-north-1)`_     no                   no                no                    no                
 `Amazon S3 (eu-west-1)`_      no                   no                no                    no                
 `Ceph RGW`_                   no                   no                no                    no                
@@ -42,6 +43,7 @@ Provider                      enable container cdn enable object cdn get contain
 .. _`Amazon S3 (ap-northeast-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-northeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-southeast-1)`: http://aws.amazon.com/s3/
+.. _`Amazon S3 (ap-southeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (cn-north-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (eu-west-1)`: http://aws.amazon.com/s3/
 .. _`Ceph RGW`: http://ceph.com/

http://git-wip-us.apache.org/repos/asf/libcloud/blob/df93d65f/docs/storage/_supported_methods_main.rst
----------------------------------------------------------------------
diff --git a/docs/storage/_supported_methods_main.rst b/docs/storage/_supported_methods_main.rst
index e0a0c1a..472bce5 100644
--- a/docs/storage/_supported_methods_main.rst
+++ b/docs/storage/_supported_methods_main.rst
@@ -18,6 +18,7 @@ Provider                      list containers list objects create container dele
 `Amazon S3 (ap-northeast-1)`_ yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
 `Amazon S3 (ap-northeast-2)`_ yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
 `Amazon S3 (ap-southeast-1)`_ yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
+`Amazon S3 (ap-southeast-2)`_ yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
 `Amazon S3 (cn-north-1)`_     yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
 `Amazon S3 (eu-west-1)`_      yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
 `Ceph RGW`_                   yes             yes          yes              yes              yes           yes                     yes             yes                       yes          
@@ -42,6 +43,7 @@ Provider                      list containers list objects create container dele
 .. _`Amazon S3 (ap-northeast-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-northeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-southeast-1)`: http://aws.amazon.com/s3/
+.. _`Amazon S3 (ap-southeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (cn-north-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (eu-west-1)`: http://aws.amazon.com/s3/
 .. _`Ceph RGW`: http://ceph.com/

http://git-wip-us.apache.org/repos/asf/libcloud/blob/df93d65f/docs/storage/_supported_providers.rst
----------------------------------------------------------------------
diff --git a/docs/storage/_supported_providers.rst b/docs/storage/_supported_providers.rst
index 9d3abc5..c04d172 100644
--- a/docs/storage/_supported_providers.rst
+++ b/docs/storage/_supported_providers.rst
@@ -18,6 +18,7 @@ Provider                      Documentation                                   Pr
 `Amazon S3 (ap-northeast-1)`_                                                 S3_AP_NORTHEAST1  single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3APNE1StorageDriver`       
 `Amazon S3 (ap-northeast-2)`_                                                 S3_AP_NORTHEAST2  single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3APNE2StorageDriver`       
 `Amazon S3 (ap-southeast-1)`_                                                 S3_AP_SOUTHEAST   single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3APSEStorageDriver`        
+`Amazon S3 (ap-southeast-2)`_                                                 S3_AP_SOUTHEAST2  single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3APSE2StorageDriver`       
 `Amazon S3 (cn-north-1)`_                                                     S3_CN_NORTH       single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3CNNorthStorageDriver`     
 `Amazon S3 (eu-west-1)`_                                                      S3_EU_WEST        single region driver         :mod:`libcloud.storage.drivers.s3`             :class:`S3EUWestStorageDriver`      
 `Ceph RGW`_                                                                   S3_RGW            single region driver         :mod:`libcloud.storage.drivers.rgw`            :class:`S3RGWStorageDriver`         
@@ -42,6 +43,7 @@ Provider                      Documentation                                   Pr
 .. _`Amazon S3 (ap-northeast-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-northeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (ap-southeast-1)`: http://aws.amazon.com/s3/
+.. _`Amazon S3 (ap-southeast-2)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (cn-north-1)`: http://aws.amazon.com/s3/
 .. _`Amazon S3 (eu-west-1)`: http://aws.amazon.com/s3/
 .. _`Ceph RGW`: http://ceph.com/


[7/9] libcloud git commit: Merge branch 'github-938' into trunk Closes #938

Posted by an...@apache.org.
Merge branch 'github-938' into trunk
Closes #938


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/ba389bdb
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/ba389bdb
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/ba389bdb

Branch: refs/heads/trunk
Commit: ba389bdb06ed4ef3d1b5dc03871282413dcb05f7
Parents: 54050a4 2569a5f
Author: Anthony Shaw <an...@apache.org>
Authored: Mon Nov 14 15:15:42 2016 +1100
Committer: Anthony Shaw <an...@apache.org>
Committed: Mon Nov 14 15:15:42 2016 +1100

----------------------------------------------------------------------
 libcloud/common/base.py                         |    2 +-
 libcloud/compute/drivers/profitbricks.py        | 4101 ++++++++++---
 .../fixtures/profitbricks/attach_volume.json    |   34 +
 .../fixtures/profitbricks/attach_volume.xml     |   12 -
 .../fixtures/profitbricks/create_node.json      |   37 +
 .../fixtures/profitbricks/create_node.xml       |   13 -
 .../fixtures/profitbricks/create_volume.json    |   35 +
 .../fixtures/profitbricks/create_volume.xml     |   13 -
 .../profitbricks/create_volume_snapshot.json    |   30 +
 .../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.json      |   20 +
 .../profitbricks/ex_create_datacenter.xml       |   13 -
 .../profitbricks/ex_create_firewall_rule.json   |   24 +
 .../profitbricks/ex_create_ip_block.json        |   22 +
 .../fixtures/profitbricks/ex_create_lan.json    |   17 +
 .../profitbricks/ex_create_load_balancer.json   |   18 +
 .../ex_create_network_interface.json            |   22 +
 .../ex_create_network_interface.xml             |   13 -
 .../profitbricks/ex_describe_datacenter.json    |  401 ++
 .../profitbricks/ex_describe_datacenter.xml     |   15 -
 .../profitbricks/ex_describe_firewall_rule.json |   24 +
 .../profitbricks/ex_describe_image.json         |   32 +
 .../profitbricks/ex_describe_ip_block.json      |   21 +
 .../fixtures/profitbricks/ex_describe_lan.json  |   24 +
 .../profitbricks/ex_describe_load_balancer.json |   25 +
 .../profitbricks/ex_describe_location.json      |   12 +
 .../ex_describe_network_interface.json          |   31 +
 .../ex_describe_network_interface.xml           |   26 -
 .../fixtures/profitbricks/ex_describe_node.json |  111 +
 .../fixtures/profitbricks/ex_describe_node.xml  |   77 -
 .../profitbricks/ex_describe_snapshot.json      |   30 +
 .../profitbricks/ex_describe_volume.json        |   35 +
 .../profitbricks/ex_describe_volume.xml         |   22 -
 .../profitbricks/ex_destroy_datacenter.xml      |   10 -
 .../ex_destroy_network_interface.xml            |   12 -
 .../profitbricks/ex_list_attached_volumes.json  |  112 +
 .../profitbricks/ex_list_datacenters.json       |   52 +
 .../profitbricks/ex_list_datacenters.xml        |   19 -
 .../profitbricks/ex_list_firewall_rules.json    |   79 +
 .../profitbricks/ex_list_ip_blocks.json         |   50 +
 .../fixtures/profitbricks/ex_list_lans.json     |  157 +
 .../ex_list_load_balanced_nics.json             |   69 +
 .../profitbricks/ex_list_load_balancers.json    |  216 +
 .../ex_list_network_interfaces.json             |   69 +
 .../profitbricks/ex_list_network_interfaces.xml |   75 -
 .../profitbricks/ex_rename_datacenter.json      |   46 +
 .../profitbricks/ex_set_inet_access.json        |   31 +
 .../fixtures/profitbricks/ex_start_node.xml     |   10 -
 .../fixtures/profitbricks/ex_stop_node.xml      |   10 -
 .../profitbricks/ex_update_datacenter.xml       |   12 -
 .../profitbricks/ex_update_firewall_rule.json   |   25 +
 .../fixtures/profitbricks/ex_update_image.json  |   32 +
 .../fixtures/profitbricks/ex_update_lan.json    |   24 +
 .../profitbricks/ex_update_load_balancer.json   |   18 +
 .../ex_update_network_interface.json            |   31 +
 .../ex_update_network_interface.xml             |   12 -
 .../fixtures/profitbricks/ex_update_node.json   |   45 +
 .../fixtures/profitbricks/ex_update_node.xml    |   12 -
 .../profitbricks/ex_update_snapshot.json        |   30 +
 .../fixtures/profitbricks/ex_update_volume.json |   35 +
 .../fixtures/profitbricks/ex_update_volume.xml  |   12 -
 .../fixtures/profitbricks/list_images.json      |  199 +
 .../fixtures/profitbricks/list_images.xml       |   43 -
 .../fixtures/profitbricks/list_locations.json   |   43 +
 .../fixtures/profitbricks/list_nodes.json       |  169 +
 .../fixtures/profitbricks/list_nodes.xml        |  172 -
 .../fixtures/profitbricks/list_snapshots.json   |   37 +
 .../fixtures/profitbricks/list_volumes.json     |  112 +
 .../fixtures/profitbricks/list_volumes.xml      |   66 -
 .../fixtures/profitbricks/reboot_node.xml       |   10 -
 libcloud/test/compute/test_profitbricks.py      | 5377 ++++++++++++++++--
 74 files changed, 10999 insertions(+), 1894 deletions(-)
----------------------------------------------------------------------