[lxc-devel] [pylxd/master] Deprecation warning

rockstar on Github lxc-bot at linuxcontainers.org
Wed Feb 17 03:32:28 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 610 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160217/9be7a069/attachment.bin>
-------------- next part --------------
From 28321e7b0b0dd30aa5468c3f02e87a1a24a6f9d0 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:03:10 -0700
Subject: [PATCH 01/15] Move api to the deprecated module

---
 pylxd/__init__.py            |   2 +
 pylxd/api.py                 | 302 -------------------------------------------
 pylxd/deprecated/__init__.py |   0
 pylxd/deprecated/api.py      | 302 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 304 insertions(+), 302 deletions(-)
 delete mode 100644 pylxd/api.py
 create mode 100644 pylxd/deprecated/__init__.py
 create mode 100644 pylxd/deprecated/api.py

diff --git a/pylxd/__init__.py b/pylxd/__init__.py
index 8de5848..0ba37c6 100644
--- a/pylxd/__init__.py
+++ b/pylxd/__init__.py
@@ -15,3 +15,5 @@
 import pbr.version
 
 __version__ = pbr.version.VersionInfo('pylxd').version_string()
+
+from pylxd.deprecated import api  # NOQA
diff --git a/pylxd/api.py b/pylxd/api.py
deleted file mode 100644
index d1be4c4..0000000
--- a/pylxd/api.py
+++ /dev/null
@@ -1,302 +0,0 @@
-
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-from pylxd import certificate
-from pylxd import connection
-from pylxd import container
-from pylxd import hosts
-from pylxd import image
-from pylxd import network
-from pylxd import operation
-from pylxd import profiles
-
-
-class API(object):
-
-    def __init__(self, host=None, port=8443):
-        conn = self.connection = connection.LXDConnection(host=host, port=port)
-        self.hosts = hosts.LXDHost(conn)
-        self.image = image.LXDImage(conn)
-        self.alias = image.LXDAlias(conn)
-        self.network = network.LXDNetwork(conn)
-        self.operation = operation.LXDOperation(conn)
-        self.profiles = profiles.LXDProfile(conn)
-        self.certificate = certificate.LXDCertificate(conn)
-        self.container = container.LXDContainer(conn)
-
-    # host
-    def host_ping(self):
-        return self.hosts.host_ping()
-
-    def host_info(self):
-        return self.hosts.host_info()
-
-    def get_lxd_api_compat(self, data=None):
-        return self.hosts.get_lxd_api_compat(data)
-
-    def get_lxd_host_trust(self, data=None):
-        return self.hosts.get_lxd_host_trust(data)
-
-    def get_lxd_backing_fs(self, data=None):
-        return self.hosts.get_lxd_backing_fs(data)
-
-    def get_lxd_driver(self, data=None):
-        return self.hosts.get_lxd_driver(data)
-
-    def get_lxc_version(self, data=None):
-        return self.hosts.get_lxc_version(data)
-
-    def get_lxd_version(self, data=None):
-        return self.hosts.get_lxd_version(data)
-
-    def get_kernel_version(self, data=None):
-        return self.hosts.get_kernel_version(data)
-
-    # images
-    def image_list(self):
-        return self.image.image_list()
-
-    def image_defined(self, image):
-        return self.image.image_defined(image)
-
-    def image_search(self, params):
-        return self.image.image_list_by_key(params)
-
-    def image_info(self, image):
-        return self.image.image_info(image)
-
-    def image_upload_date(self, image, data=None):
-        return self.image.get_image_date(image, data, 'uploaded_at')
-
-    def image_create_date(self, image, data=None):
-        return self.image.get_image_date(image, data, 'created_at')
-
-    def image_expire_date(self, image, data=None):
-        return self.image.get_image_date(image, data, 'expires_at')
-
-    def image_upload(self, path=None, data=None, headers={}):
-        return self.image.image_upload(path=path, data=data, headers=headers)
-
-    def image_delete(self, image):
-        return self.image.image_delete(image)
-
-    def image_export(self, image):
-        return self.image.image_export(image)
-
-    def image_update(self, image, data):
-        return self.image.image_update(image, data)
-
-    def image_rename(self, image, data):
-        return self.image.image_rename(image, data)
-
-    # alias
-    def alias_list(self):
-        return self.alias.alias_list()
-
-    def alias_defined(self, alias):
-        return self.alias.alias_defined(alias)
-
-    def alias_create(self, data):
-        return self.alias.alias_create(data)
-
-    def alias_update(self, alias, data):
-        return self.alias.alias_update(alias, data)
-
-    def alias_show(self, alias):
-        return self.alias.alias_show(alias)
-
-    def alias_rename(self, alias, data):
-        return self.alias.alias_rename(alias, data)
-
-    def alias_delete(self, alias):
-        return self.alias.alias_delete(alias)
-
-    # containers:
-    def container_list(self):
-        return self.container.container_list()
-
-    def container_defined(self, container):
-        return self.container.container_defined(container)
-
-    def container_running(self, container):
-        return self.container.container_running(container)
-
-    def container_init(self, container):
-        return self.container.container_init(container)
-
-    def container_update(self, container, config):
-        return self.container.container_update(container, config)
-
-    def container_state(self, container):
-        return self.container.container_state(container)
-
-    def container_start(self, container, timeout):
-        return self.container.container_start(container, timeout)
-
-    def container_stop(self, container, timeout):
-        return self.container.container_stop(container, timeout)
-
-    def container_suspend(self, container, timeout):
-        return self.container.container_suspend(container, timeout)
-
-    def container_resume(self, container, timeout):
-        return self.container.container_resume(container, timeout)
-
-    def container_reboot(self, container, timeout):
-        return self.container.container_reboot(container, timeout)
-
-    def container_destroy(self, container):
-        return self.container.container_destroy(container)
-
-    def get_container_log(self, container):
-        return self.container.get_container_log(container)
-
-    def get_container_config(self, container):
-        return self.container.get_container_config(container)
-
-    def get_container_websocket(self, container):
-        return self.container.get_container_websocket(container)
-
-    def container_info(self, container):
-        return self.container.container_info(container)
-
-    def container_local_copy(self, container):
-        return self.container.container_local_copy(container)
-
-    def container_local_move(self, instance, container):
-        return self.container.container_local_move(instance, container)
-
-    # file operations
-    def get_container_file(self, container, filename):
-        return self.container.get_container_file(container, filename)
-
-    def container_publish(self, container):
-        return self.container.container_publish(container)
-
-    def put_container_file(self, container, src_file,
-                           dst_file, uid=0, gid=0, mode=0o644):
-        return self.container.put_container_file(
-            container, src_file, dst_file, uid, gid, mode)
-
-    # snapshots
-    def container_snapshot_list(self, container):
-        return self.container.snapshot_list(container)
-
-    def container_snapshot_create(self, container, config):
-        return self.container.snapshot_create(container, config)
-
-    def container_snapshot_info(self, container, snapshot):
-        return self.container.snapshot_info(container, snapshot)
-
-    def container_snapshot_rename(self, container, snapshot, config):
-        return self.container.snapshot_rename(container, snapshot, config)
-
-    def container_snapshot_delete(self, container, snapshot):
-        return self.container.snapshot_delete(container, snapshot)
-
-    def container_migrate(self, container):
-        return self.container.container_migrate(container)
-
-    def container_migrate_sync(self, operation_id, container_secret):
-        return self.container.container_migrate_sync(
-            operation_id, container_secret)
-
-    # misc container
-    def container_run_command(self, container, args, interactive=False,
-                              web_sockets=False, env=None):
-        return self.container.run_command(container, args, interactive,
-                                          web_sockets, env)
-
-    # certificates
-    def certificate_list(self):
-        return self.certificate.certificate_list()
-
-    def certificate_show(self, fingerprint):
-        return self.certificate.certificate_show(fingerprint)
-
-    def certificate_delete(self, fingerprint):
-        return self.certificate.certificate_delete(fingerprint)
-
-    def certificate_create(self, fingerprint):
-        return self.certificate.certificate_create(fingerprint)
-
-    # profiles
-    def profile_create(self, profile):
-        '''Create LXD profile'''
-        return self.profiles.profile_create(profile)
-
-    def profile_show(self, profile):
-        '''Show LXD profile'''
-        return self.profiles.profile_show(profile)
-
-    def profile_defined(self, profile):
-        '''Check to see if profile is defined'''
-        return self.profiles.profile_defined(profile)
-
-    def profile_list(self):
-        '''List LXD profiles'''
-        return self.profiles.profile_list()
-
-    def profile_update(self, profile, config):
-        '''Update LXD profile'''
-        return self.profiles.profile_update(profile, config)
-
-    def profile_rename(self, profile, config):
-        '''Rename LXD profile'''
-        return self.profiles.profile_rename(profile, config)
-
-    def profile_delete(self, profile):
-        '''Delete LXD profile'''
-        return self.profiles.profile_delete(profile)
-
-    # lxd operations
-    def list_operations(self):
-        return self.operation.operation_list()
-
-    def wait_container_operation(self, operation, status_code, timeout):
-        return self.operation.operation_wait(operation, status_code, timeout)
-
-    def operation_delete(self, operation):
-        return self.operation.operation_delete(operation)
-
-    def operation_info(self, operation):
-        return self.operation.operation_info(operation)
-
-    def operation_show_create_time(self, operation, data=None):
-        return self.operation.operation_create_time(operation, data)
-
-    def operation_show_update_time(self, operation, data=None):
-        return self.operation.operation_update_time(operation, data)
-
-    def operation_show_status(self, operation, data=None):
-        return self.operation.operation_status_code(operation, data)
-
-    def operation_stream(self, operation, operation_secret):
-        return self.operation.operation_stream(operation, operation_secret)
-
-    # networks
-    def network_list(self):
-        return self.network.network_list()
-
-    def network_show(self, network):
-        return self.network.network_show(network)
-
-    def network_show_name(self, network, data=None):
-        return self.network.show_network_name(network, data)
-
-    def network_show_type(self, network, data=None):
-        return self.network.show_network_type(network, data)
-
-    def network_show_members(self, network, data=None):
-        return self.network.show_network_members(network, data)
diff --git a/pylxd/deprecated/__init__.py b/pylxd/deprecated/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
new file mode 100644
index 0000000..d1be4c4
--- /dev/null
+++ b/pylxd/deprecated/api.py
@@ -0,0 +1,302 @@
+
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from pylxd import certificate
+from pylxd import connection
+from pylxd import container
+from pylxd import hosts
+from pylxd import image
+from pylxd import network
+from pylxd import operation
+from pylxd import profiles
+
+
+class API(object):
+
+    def __init__(self, host=None, port=8443):
+        conn = self.connection = connection.LXDConnection(host=host, port=port)
+        self.hosts = hosts.LXDHost(conn)
+        self.image = image.LXDImage(conn)
+        self.alias = image.LXDAlias(conn)
+        self.network = network.LXDNetwork(conn)
+        self.operation = operation.LXDOperation(conn)
+        self.profiles = profiles.LXDProfile(conn)
+        self.certificate = certificate.LXDCertificate(conn)
+        self.container = container.LXDContainer(conn)
+
+    # host
+    def host_ping(self):
+        return self.hosts.host_ping()
+
+    def host_info(self):
+        return self.hosts.host_info()
+
+    def get_lxd_api_compat(self, data=None):
+        return self.hosts.get_lxd_api_compat(data)
+
+    def get_lxd_host_trust(self, data=None):
+        return self.hosts.get_lxd_host_trust(data)
+
+    def get_lxd_backing_fs(self, data=None):
+        return self.hosts.get_lxd_backing_fs(data)
+
+    def get_lxd_driver(self, data=None):
+        return self.hosts.get_lxd_driver(data)
+
+    def get_lxc_version(self, data=None):
+        return self.hosts.get_lxc_version(data)
+
+    def get_lxd_version(self, data=None):
+        return self.hosts.get_lxd_version(data)
+
+    def get_kernel_version(self, data=None):
+        return self.hosts.get_kernel_version(data)
+
+    # images
+    def image_list(self):
+        return self.image.image_list()
+
+    def image_defined(self, image):
+        return self.image.image_defined(image)
+
+    def image_search(self, params):
+        return self.image.image_list_by_key(params)
+
+    def image_info(self, image):
+        return self.image.image_info(image)
+
+    def image_upload_date(self, image, data=None):
+        return self.image.get_image_date(image, data, 'uploaded_at')
+
+    def image_create_date(self, image, data=None):
+        return self.image.get_image_date(image, data, 'created_at')
+
+    def image_expire_date(self, image, data=None):
+        return self.image.get_image_date(image, data, 'expires_at')
+
+    def image_upload(self, path=None, data=None, headers={}):
+        return self.image.image_upload(path=path, data=data, headers=headers)
+
+    def image_delete(self, image):
+        return self.image.image_delete(image)
+
+    def image_export(self, image):
+        return self.image.image_export(image)
+
+    def image_update(self, image, data):
+        return self.image.image_update(image, data)
+
+    def image_rename(self, image, data):
+        return self.image.image_rename(image, data)
+
+    # alias
+    def alias_list(self):
+        return self.alias.alias_list()
+
+    def alias_defined(self, alias):
+        return self.alias.alias_defined(alias)
+
+    def alias_create(self, data):
+        return self.alias.alias_create(data)
+
+    def alias_update(self, alias, data):
+        return self.alias.alias_update(alias, data)
+
+    def alias_show(self, alias):
+        return self.alias.alias_show(alias)
+
+    def alias_rename(self, alias, data):
+        return self.alias.alias_rename(alias, data)
+
+    def alias_delete(self, alias):
+        return self.alias.alias_delete(alias)
+
+    # containers:
+    def container_list(self):
+        return self.container.container_list()
+
+    def container_defined(self, container):
+        return self.container.container_defined(container)
+
+    def container_running(self, container):
+        return self.container.container_running(container)
+
+    def container_init(self, container):
+        return self.container.container_init(container)
+
+    def container_update(self, container, config):
+        return self.container.container_update(container, config)
+
+    def container_state(self, container):
+        return self.container.container_state(container)
+
+    def container_start(self, container, timeout):
+        return self.container.container_start(container, timeout)
+
+    def container_stop(self, container, timeout):
+        return self.container.container_stop(container, timeout)
+
+    def container_suspend(self, container, timeout):
+        return self.container.container_suspend(container, timeout)
+
+    def container_resume(self, container, timeout):
+        return self.container.container_resume(container, timeout)
+
+    def container_reboot(self, container, timeout):
+        return self.container.container_reboot(container, timeout)
+
+    def container_destroy(self, container):
+        return self.container.container_destroy(container)
+
+    def get_container_log(self, container):
+        return self.container.get_container_log(container)
+
+    def get_container_config(self, container):
+        return self.container.get_container_config(container)
+
+    def get_container_websocket(self, container):
+        return self.container.get_container_websocket(container)
+
+    def container_info(self, container):
+        return self.container.container_info(container)
+
+    def container_local_copy(self, container):
+        return self.container.container_local_copy(container)
+
+    def container_local_move(self, instance, container):
+        return self.container.container_local_move(instance, container)
+
+    # file operations
+    def get_container_file(self, container, filename):
+        return self.container.get_container_file(container, filename)
+
+    def container_publish(self, container):
+        return self.container.container_publish(container)
+
+    def put_container_file(self, container, src_file,
+                           dst_file, uid=0, gid=0, mode=0o644):
+        return self.container.put_container_file(
+            container, src_file, dst_file, uid, gid, mode)
+
+    # snapshots
+    def container_snapshot_list(self, container):
+        return self.container.snapshot_list(container)
+
+    def container_snapshot_create(self, container, config):
+        return self.container.snapshot_create(container, config)
+
+    def container_snapshot_info(self, container, snapshot):
+        return self.container.snapshot_info(container, snapshot)
+
+    def container_snapshot_rename(self, container, snapshot, config):
+        return self.container.snapshot_rename(container, snapshot, config)
+
+    def container_snapshot_delete(self, container, snapshot):
+        return self.container.snapshot_delete(container, snapshot)
+
+    def container_migrate(self, container):
+        return self.container.container_migrate(container)
+
+    def container_migrate_sync(self, operation_id, container_secret):
+        return self.container.container_migrate_sync(
+            operation_id, container_secret)
+
+    # misc container
+    def container_run_command(self, container, args, interactive=False,
+                              web_sockets=False, env=None):
+        return self.container.run_command(container, args, interactive,
+                                          web_sockets, env)
+
+    # certificates
+    def certificate_list(self):
+        return self.certificate.certificate_list()
+
+    def certificate_show(self, fingerprint):
+        return self.certificate.certificate_show(fingerprint)
+
+    def certificate_delete(self, fingerprint):
+        return self.certificate.certificate_delete(fingerprint)
+
+    def certificate_create(self, fingerprint):
+        return self.certificate.certificate_create(fingerprint)
+
+    # profiles
+    def profile_create(self, profile):
+        '''Create LXD profile'''
+        return self.profiles.profile_create(profile)
+
+    def profile_show(self, profile):
+        '''Show LXD profile'''
+        return self.profiles.profile_show(profile)
+
+    def profile_defined(self, profile):
+        '''Check to see if profile is defined'''
+        return self.profiles.profile_defined(profile)
+
+    def profile_list(self):
+        '''List LXD profiles'''
+        return self.profiles.profile_list()
+
+    def profile_update(self, profile, config):
+        '''Update LXD profile'''
+        return self.profiles.profile_update(profile, config)
+
+    def profile_rename(self, profile, config):
+        '''Rename LXD profile'''
+        return self.profiles.profile_rename(profile, config)
+
+    def profile_delete(self, profile):
+        '''Delete LXD profile'''
+        return self.profiles.profile_delete(profile)
+
+    # lxd operations
+    def list_operations(self):
+        return self.operation.operation_list()
+
+    def wait_container_operation(self, operation, status_code, timeout):
+        return self.operation.operation_wait(operation, status_code, timeout)
+
+    def operation_delete(self, operation):
+        return self.operation.operation_delete(operation)
+
+    def operation_info(self, operation):
+        return self.operation.operation_info(operation)
+
+    def operation_show_create_time(self, operation, data=None):
+        return self.operation.operation_create_time(operation, data)
+
+    def operation_show_update_time(self, operation, data=None):
+        return self.operation.operation_update_time(operation, data)
+
+    def operation_show_status(self, operation, data=None):
+        return self.operation.operation_status_code(operation, data)
+
+    def operation_stream(self, operation, operation_secret):
+        return self.operation.operation_stream(operation, operation_secret)
+
+    # networks
+    def network_list(self):
+        return self.network.network_list()
+
+    def network_show(self, network):
+        return self.network.network_show(network)
+
+    def network_show_name(self, network, data=None):
+        return self.network.show_network_name(network, data)
+
+    def network_show_type(self, network, data=None):
+        return self.network.show_network_type(network, data)
+
+    def network_show_members(self, network, data=None):
+        return self.network.show_network_members(network, data)

From 86cbcb420f6df4aea4793e41a8b9112b04661c54 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:12:39 -0700
Subject: [PATCH 02/15] API now raises a DeprecationWarning

---
 pylxd/deprecated/api.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index d1be4c4..624ce4b 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -12,6 +12,8 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+import warnings
+
 from pylxd import certificate
 from pylxd import connection
 from pylxd import container
@@ -25,6 +27,9 @@
 class API(object):
 
     def __init__(self, host=None, port=8443):
+        warnings.warn(
+            "pylxd.api.API is deprecated. Please use pylxd.Client.",
+            DeprecationWarning)
         conn = self.connection = connection.LXDConnection(host=host, port=port)
         self.hosts = hosts.LXDHost(conn)
         self.image = image.LXDImage(conn)

From 9e685fd38f87da6e88f22de9d6c60451b8d7a00c Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:19:56 -0700
Subject: [PATCH 03/15] Move base to deprecated

---
 pylxd/base.py            | 22 ----------------------
 pylxd/certificate.py     |  2 +-
 pylxd/container.py       |  2 +-
 pylxd/deprecated/base.py | 22 ++++++++++++++++++++++
 pylxd/hosts.py           |  2 +-
 pylxd/image.py           |  2 +-
 pylxd/network.py         |  2 +-
 pylxd/operation.py       |  2 +-
 pylxd/profiles.py        |  2 +-
 9 files changed, 29 insertions(+), 29 deletions(-)
 delete mode 100644 pylxd/base.py
 create mode 100644 pylxd/deprecated/base.py

diff --git a/pylxd/base.py b/pylxd/base.py
deleted file mode 100644
index 689e80e..0000000
--- a/pylxd/base.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-from __future__ import print_function
-
-from pylxd import connection
-
-
-class LXDBase(object):
-
-    def __init__(self, conn=None):
-        self.connection = conn or connection.LXDConnection()
diff --git a/pylxd/certificate.py b/pylxd/certificate.py
index b937009..79564a0 100644
--- a/pylxd/certificate.py
+++ b/pylxd/certificate.py
@@ -14,7 +14,7 @@
 
 import json
 
-from pylxd import base
+from pylxd.deprecated import base
 
 
 class LXDCertificate(base.LXDBase):
diff --git a/pylxd/container.py b/pylxd/container.py
index 25c2955..e7ec13a 100644
--- a/pylxd/container.py
+++ b/pylxd/container.py
@@ -15,7 +15,7 @@
 
 import six
 
-from pylxd import base
+from pylxd.deprecated import base
 from pylxd import exceptions
 from pylxd import mixin
 from pylxd.operation import Operation
diff --git a/pylxd/deprecated/base.py b/pylxd/deprecated/base.py
new file mode 100644
index 0000000..689e80e
--- /dev/null
+++ b/pylxd/deprecated/base.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from __future__ import print_function
+
+from pylxd import connection
+
+
+class LXDBase(object):
+
+    def __init__(self, conn=None):
+        self.connection = conn or connection.LXDConnection()
diff --git a/pylxd/hosts.py b/pylxd/hosts.py
index 64bd57b..e882bff 100644
--- a/pylxd/hosts.py
+++ b/pylxd/hosts.py
@@ -13,7 +13,7 @@
 #    under the License.
 from __future__ import print_function
 
-from pylxd import base
+from pylxd.deprecated import base
 from pylxd import exceptions
 
 
diff --git a/pylxd/image.py b/pylxd/image.py
index d2b3b6b..b9a3c21 100644
--- a/pylxd/image.py
+++ b/pylxd/image.py
@@ -17,7 +17,7 @@
 import json
 from six.moves import urllib
 
-from pylxd import base
+from pylxd.deprecated import base
 from pylxd import connection
 from pylxd import exceptions
 from pylxd import mixin
diff --git a/pylxd/network.py b/pylxd/network.py
index 8743d80..3eff79e 100644
--- a/pylxd/network.py
+++ b/pylxd/network.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from pylxd import base
+from pylxd.deprecated import base
 
 
 class LXDNetwork(base.LXDBase):
diff --git a/pylxd/operation.py b/pylxd/operation.py
index 483efd3..27766f6 100644
--- a/pylxd/operation.py
+++ b/pylxd/operation.py
@@ -14,7 +14,7 @@
 
 from dateutil.parser import parse as parse_date
 
-from pylxd import base
+from pylxd.deprecated import base
 
 
 class LXDOperation(base.LXDBase):
diff --git a/pylxd/profiles.py b/pylxd/profiles.py
index b4a76e3..da39c2b 100644
--- a/pylxd/profiles.py
+++ b/pylxd/profiles.py
@@ -14,7 +14,7 @@
 # XXX: rockstar (15 Feb 2016) - This module should be renamed to 'profile'.
 import json
 
-from pylxd import base
+from pylxd.deprecated import base
 from pylxd import mixin
 
 

From d92152ed02acca0ac0be46f413aa32a43f30a473 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:30:40 -0700
Subject: [PATCH 04/15] Move pylxd.container.LXDContainer to
 pylxd.deprecated.container

---
 pylxd/container.py            | 194 +--------------------------------------
 pylxd/deprecated/container.py | 206 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+), 192 deletions(-)
 create mode 100644 pylxd/deprecated/container.py

diff --git a/pylxd/container.py b/pylxd/container.py
index e7ec13a..2b4a93e 100644
--- a/pylxd/container.py
+++ b/pylxd/container.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 Canonical Ltd
+# Copyright (c) 2016 Canonical Ltd
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -11,204 +11,14 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-import json
 
 import six
 
-from pylxd.deprecated import base
-from pylxd import exceptions
 from pylxd import mixin
+from pylxd.deprecated.container import LXDContainer  # NOQA
 from pylxd.operation import Operation
 
 
-class LXDContainer(base.LXDBase):
-    # containers:
-
-    def container_list(self):
-        (state, data) = self.connection.get_object('GET', '/1.0/containers')
-        return [container.split('/1.0/containers/')[-1]
-                for container in data['metadata']]
-
-    def container_running(self, container):
-        (state, data) = self.connection.get_object(
-            'GET',
-            '/1.0/containers/%s/state' % container)
-        data = data.get('metadata')
-        container_running = False
-        if data['status'].upper() in ['RUNNING', 'STARTING', 'FREEZING',
-                                      'FROZEN', 'THAWED']:
-            container_running = True
-        return container_running
-
-    def container_init(self, container):
-        return self.connection.get_object('POST', '/1.0/containers',
-                                          json.dumps(container))
-
-    def container_update(self, container, config):
-        return self.connection.get_object('PUT', '/1.0/containers/%s'
-                                          % container, json.dumps(config))
-
-    def container_defined(self, container):
-        _, data = self.connection.get_object('GET', '/1.0/containers')
-        try:
-            containers = data["metadata"]
-        except KeyError:
-            raise exceptions.PyLXDException("no metadata in GET containers?")
-
-        container_url = "/1.0/containers/%s" % container
-        for ct in containers:
-            if ct == container_url:
-                return True
-        return False
-
-    def container_state(self, container):
-        return self.connection.get_object(
-            'GET', '/1.0/containers/%s/state' % container)
-
-    def container_start(self, container, timeout):
-        action = {'action': 'start', 'force': True, 'timeout': timeout}
-        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
-                                          % container,
-                                          json.dumps(action))
-
-    def container_stop(self, container, timeout):
-        action = {'action': 'stop', 'force': True, 'timeout': timeout}
-        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
-                                          % container,
-                                          json.dumps(action))
-
-    def container_suspend(self, container, timeout):
-        action = {'action': 'freeze', 'force': True, 'timeout': timeout}
-        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
-                                          % container,
-                                          json.dumps(action))
-
-    def container_resume(self, container, timeout):
-        action = {'action': 'unfreeze', 'force': True, 'timeout': timeout}
-        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
-                                          % container,
-                                          json.dumps(action))
-
-    def container_reboot(self, container, timeout):
-        action = {'action': 'restart', 'force': True, 'timeout': timeout}
-        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
-                                          % container,
-                                          json.dumps(action))
-
-    def container_destroy(self, container):
-        return self.connection.get_object('DELETE', '/1.0/containers/%s'
-                                          % container)
-
-    def get_container_log(self, container):
-        (state, data) = self.connection.get_object(
-            'GET', '/1.0/containers/%s?log=true' % container)
-        return data['metadata']['log']
-
-    def get_container_config(self, container):
-        (state, data) = self.connection.get_object(
-            'GET', '/1.0/containers/%s?log=false' % container)
-        return data['metadata']
-
-    def get_container_websocket(self, container):
-        return self.connection.get_status(
-            'GET',
-            '/1.0/operations/%s/websocket?secret=%s'
-            % (container['operation'], container['fs']))
-
-    def container_info(self, container):
-        (state, data) = self.connection.get_object(
-            'GET', '/1.0/containers/%s/state' % container)
-        return data['metadata']
-
-    def container_migrate(self, container):
-        action = {'migration': True}
-        (state, data) = self.connection.get_object(
-            'POST', '/1.0/containers/%s' % container,
-            json.dumps(action))
-
-        return_data = {
-            'operation': str(data['operation'].split('/1.0/operations/')[-1]),
-        }
-        return_data.update(data['metadata'])
-        return return_data
-
-    def container_migrate_sync(self, operation_id, container_secret):
-        return self.connection.get_ws(
-            '/1.0/operations/%s/websocket?secret=%s'
-            % (operation_id, container_secret))
-
-    def container_local_copy(self, container):
-        return self.connection.get_object(
-            'POST',
-            '/1.0/containers', json.dumps(container))
-
-    def container_local_move(self, instance, config):
-        return self.connection.get_object(
-            'POST',
-            '/1.0/containers/%s' % instance, json.dumps(config))
-
-    # file operations
-    def get_container_file(self, container, filename):
-        return self.connection.get_raw(
-            'GET',
-            '/1.0/containers/%s/files?path=%s' % (container, filename))
-
-    def put_container_file(self, container, src_file,
-                           dst_file, uid, gid, mode):
-        with open(src_file, 'rb') as f:
-            data = f.read()
-        return self.connection.get_object(
-            'POST',
-            '/1.0/containers/%s/files?path=%s' % (container, dst_file),
-            body=data,
-            headers={'X-LXD-uid': uid, 'X-LXD-gid': gid, 'X-LXD-mode': mode})
-
-    def container_publish(self, container):
-        return self.connection.get_object('POST', '/1.0/images',
-                                          json.dumps(container))
-
-    # misc operations
-    def run_command(self, container, args, interactive, web_sockets, env):
-        env = env or {}
-        data = {'command': args,
-                'interactive': interactive,
-                'wait-for-websocket': web_sockets,
-                'environment': env}
-        return self.connection.get_object('POST', '/1.0/containers/%s/exec'
-                                          % container, json.dumps(data))
-
-    # snapshots
-    def snapshot_list(self, container):
-        (state, data) = self.connection.get_object(
-            'GET',
-            '/1.0/containers/%s/snapshots' % container)
-        return [snapshot.split('/1.0/containers/%s/snapshots/%s/'
-                               % (container, container))[-1]
-                for snapshot in data['metadata']]
-
-    def snapshot_create(self, container, config):
-        return self.connection.get_object('POST',
-                                          '/1.0/containers/%s/snapshots'
-                                          % container,
-                                          json.dumps(config))
-
-    def snapshot_info(self, container, snapshot):
-        return self.connection.get_object('GET',
-                                          '/1.0/containers/%s/snapshots/%s'
-                                          % (container, snapshot))
-
-    def snapshot_rename(self, container, snapshot, config):
-        return self.connection.get_object('POST',
-                                          '/1.0/containers/%s/snapshots/%s'
-                                          % (container, snapshot),
-                                          json.dumps(config))
-
-    def snapshot_delete(self, container, snapshot):
-        return self.connection.get_object('DELETE',
-                                          '/1.0/containers/%s/snapshots/%s'
-                                          % (container, snapshot))
-
-
 class Container(mixin.Waitable, mixin.Marshallable):
     """An LXD Container.
 
diff --git a/pylxd/deprecated/container.py b/pylxd/deprecated/container.py
new file mode 100644
index 0000000..037ebdd
--- /dev/null
+++ b/pylxd/deprecated/container.py
@@ -0,0 +1,206 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from pylxd.deprecated import base
+from pylxd import exceptions
+
+
+class LXDContainer(base.LXDBase):
+    # containers:
+
+    def container_list(self):
+        (state, data) = self.connection.get_object('GET', '/1.0/containers')
+        return [container.split('/1.0/containers/')[-1]
+                for container in data['metadata']]
+
+    def container_running(self, container):
+        (state, data) = self.connection.get_object(
+            'GET',
+            '/1.0/containers/%s/state' % container)
+        data = data.get('metadata')
+        container_running = False
+        if data['status'].upper() in ['RUNNING', 'STARTING', 'FREEZING',
+                                      'FROZEN', 'THAWED']:
+            container_running = True
+        return container_running
+
+    def container_init(self, container):
+        return self.connection.get_object('POST', '/1.0/containers',
+                                          json.dumps(container))
+
+    def container_update(self, container, config):
+        return self.connection.get_object('PUT', '/1.0/containers/%s'
+                                          % container, json.dumps(config))
+
+    def container_defined(self, container):
+        _, data = self.connection.get_object('GET', '/1.0/containers')
+        try:
+            containers = data["metadata"]
+        except KeyError:
+            raise exceptions.PyLXDException("no metadata in GET containers?")
+
+        container_url = "/1.0/containers/%s" % container
+        for ct in containers:
+            if ct == container_url:
+                return True
+        return False
+
+    def container_state(self, container):
+        return self.connection.get_object(
+            'GET', '/1.0/containers/%s/state' % container)
+
+    def container_start(self, container, timeout):
+        action = {'action': 'start', 'force': True, 'timeout': timeout}
+        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
+                                          % container,
+                                          json.dumps(action))
+
+    def container_stop(self, container, timeout):
+        action = {'action': 'stop', 'force': True, 'timeout': timeout}
+        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
+                                          % container,
+                                          json.dumps(action))
+
+    def container_suspend(self, container, timeout):
+        action = {'action': 'freeze', 'force': True, 'timeout': timeout}
+        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
+                                          % container,
+                                          json.dumps(action))
+
+    def container_resume(self, container, timeout):
+        action = {'action': 'unfreeze', 'force': True, 'timeout': timeout}
+        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
+                                          % container,
+                                          json.dumps(action))
+
+    def container_reboot(self, container, timeout):
+        action = {'action': 'restart', 'force': True, 'timeout': timeout}
+        return self.connection.get_object('PUT', '/1.0/containers/%s/state'
+                                          % container,
+                                          json.dumps(action))
+
+    def container_destroy(self, container):
+        return self.connection.get_object('DELETE', '/1.0/containers/%s'
+                                          % container)
+
+    def get_container_log(self, container):
+        (state, data) = self.connection.get_object(
+            'GET', '/1.0/containers/%s?log=true' % container)
+        return data['metadata']['log']
+
+    def get_container_config(self, container):
+        (state, data) = self.connection.get_object(
+            'GET', '/1.0/containers/%s?log=false' % container)
+        return data['metadata']
+
+    def get_container_websocket(self, container):
+        return self.connection.get_status(
+            'GET',
+            '/1.0/operations/%s/websocket?secret=%s'
+            % (container['operation'], container['fs']))
+
+    def container_info(self, container):
+        (state, data) = self.connection.get_object(
+            'GET', '/1.0/containers/%s/state' % container)
+        return data['metadata']
+
+    def container_migrate(self, container):
+        action = {'migration': True}
+        (state, data) = self.connection.get_object(
+            'POST', '/1.0/containers/%s' % container,
+            json.dumps(action))
+
+        return_data = {
+            'operation': str(data['operation'].split('/1.0/operations/')[-1]),
+        }
+        return_data.update(data['metadata'])
+        return return_data
+
+    def container_migrate_sync(self, operation_id, container_secret):
+        return self.connection.get_ws(
+            '/1.0/operations/%s/websocket?secret=%s'
+            % (operation_id, container_secret))
+
+    def container_local_copy(self, container):
+        return self.connection.get_object(
+            'POST',
+            '/1.0/containers', json.dumps(container))
+
+    def container_local_move(self, instance, config):
+        return self.connection.get_object(
+            'POST',
+            '/1.0/containers/%s' % instance, json.dumps(config))
+
+    # file operations
+    def get_container_file(self, container, filename):
+        return self.connection.get_raw(
+            'GET',
+            '/1.0/containers/%s/files?path=%s' % (container, filename))
+
+    def put_container_file(self, container, src_file,
+                           dst_file, uid, gid, mode):
+        with open(src_file, 'rb') as f:
+            data = f.read()
+        return self.connection.get_object(
+            'POST',
+            '/1.0/containers/%s/files?path=%s' % (container, dst_file),
+            body=data,
+            headers={'X-LXD-uid': uid, 'X-LXD-gid': gid, 'X-LXD-mode': mode})
+
+    def container_publish(self, container):
+        return self.connection.get_object('POST', '/1.0/images',
+                                          json.dumps(container))
+
+    # misc operations
+    def run_command(self, container, args, interactive, web_sockets, env):
+        env = env or {}
+        data = {'command': args,
+                'interactive': interactive,
+                'wait-for-websocket': web_sockets,
+                'environment': env}
+        return self.connection.get_object('POST', '/1.0/containers/%s/exec'
+                                          % container, json.dumps(data))
+
+    # snapshots
+    def snapshot_list(self, container):
+        (state, data) = self.connection.get_object(
+            'GET',
+            '/1.0/containers/%s/snapshots' % container)
+        return [snapshot.split('/1.0/containers/%s/snapshots/%s/'
+                               % (container, container))[-1]
+                for snapshot in data['metadata']]
+
+    def snapshot_create(self, container, config):
+        return self.connection.get_object('POST',
+                                          '/1.0/containers/%s/snapshots'
+                                          % container,
+                                          json.dumps(config))
+
+    def snapshot_info(self, container, snapshot):
+        return self.connection.get_object('GET',
+                                          '/1.0/containers/%s/snapshots/%s'
+                                          % (container, snapshot))
+
+    def snapshot_rename(self, container, snapshot, config):
+        return self.connection.get_object('POST',
+                                          '/1.0/containers/%s/snapshots/%s'
+                                          % (container, snapshot),
+                                          json.dumps(config))
+
+    def snapshot_delete(self, container, snapshot):
+        return self.connection.get_object('DELETE',
+                                          '/1.0/containers/%s/snapshots/%s'
+                                          % (container, snapshot))

From 35ee55764759da80614dc5b5a99bf8dbb04f4323 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:34:58 -0700
Subject: [PATCH 05/15] Move pylxd.certificate to pylxd.deprecated.certificate

---
 pylxd/certificate.py            | 37 -------------------------------------
 pylxd/deprecated/api.py         |  4 ++--
 pylxd/deprecated/certificate.py | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 39 deletions(-)
 delete mode 100644 pylxd/certificate.py
 create mode 100644 pylxd/deprecated/certificate.py

diff --git a/pylxd/certificate.py b/pylxd/certificate.py
deleted file mode 100644
index 79564a0..0000000
--- a/pylxd/certificate.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import json
-
-from pylxd.deprecated import base
-
-
-class LXDCertificate(base.LXDBase):
-
-    def certificate_list(self):
-        (state, data) = self.connection.get_object('GET', '/1.0/certificates')
-        return [certificate.split('/1.0/certificates/')[-1]
-                for certificate in data['metadata']]
-
-    def certificate_show(self, fingerprint):
-        return self.connection.get_object('GET', '/1.0/certificates/%s'
-                                          % fingerprint)
-
-    def certificate_create(self, certificate):
-        return self.connection.get_status('POST', '/1.0/certificates',
-                                          json.dumps(certificate))
-
-    def certificate_delete(self, fingerprint):
-        return self.connection.get_status('DELETE', '/1.0/certificates/%s'
-                                          % fingerprint)
diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 624ce4b..8ff8fbb 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -14,9 +14,9 @@
 #    under the License.
 import warnings
 
-from pylxd import certificate
+from pylxd.deprecated import certificate
 from pylxd import connection
-from pylxd import container
+from pylxd.deprecated import container
 from pylxd import hosts
 from pylxd import image
 from pylxd import network
diff --git a/pylxd/deprecated/certificate.py b/pylxd/deprecated/certificate.py
new file mode 100644
index 0000000..79564a0
--- /dev/null
+++ b/pylxd/deprecated/certificate.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from pylxd.deprecated import base
+
+
+class LXDCertificate(base.LXDBase):
+
+    def certificate_list(self):
+        (state, data) = self.connection.get_object('GET', '/1.0/certificates')
+        return [certificate.split('/1.0/certificates/')[-1]
+                for certificate in data['metadata']]
+
+    def certificate_show(self, fingerprint):
+        return self.connection.get_object('GET', '/1.0/certificates/%s'
+                                          % fingerprint)
+
+    def certificate_create(self, certificate):
+        return self.connection.get_status('POST', '/1.0/certificates',
+                                          json.dumps(certificate))
+
+    def certificate_delete(self, fingerprint):
+        return self.connection.get_status('DELETE', '/1.0/certificates/%s'
+                                          % fingerprint)

From 95927a07f50ebdb9aba095039f827e83205c86c1 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:46:18 -0700
Subject: [PATCH 06/15] Move pylxd.connection import
 pylxd.deprecated.connection

---
 pylxd/connection.py             | 222 ----------------------------------------
 pylxd/deprecated/api.py         |   2 +-
 pylxd/deprecated/base.py        |   2 +-
 pylxd/deprecated/connection.py  | 222 ++++++++++++++++++++++++++++++++++++++++
 pylxd/image.py                  |   2 +-
 pylxd/tests/test_certificate.py |   2 +-
 pylxd/tests/test_connection.py  |  10 +-
 pylxd/tests/test_container.py   |   2 +-
 pylxd/tests/test_host.py        |   2 +-
 pylxd/tests/test_image.py       |   2 +-
 pylxd/tests/test_image_alias.py |   2 +-
 pylxd/tests/test_network.py     |   2 +-
 pylxd/tests/test_operation.py   |   2 +-
 pylxd/tests/test_profiles.py    |   2 +-
 14 files changed, 238 insertions(+), 238 deletions(-)
 delete mode 100644 pylxd/connection.py
 create mode 100644 pylxd/deprecated/connection.py

diff --git a/pylxd/connection.py b/pylxd/connection.py
deleted file mode 100644
index c1b9ea1..0000000
--- a/pylxd/connection.py
+++ /dev/null
@@ -1,222 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-# Copyright (c) 2015 Mirantis inc.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from collections import namedtuple
-import copy
-import json
-import os
-import six
-import socket
-import ssl
-import threading
-
-
-from pylxd import exceptions
-from pylxd import utils
-from six.moves import http_client
-from six.moves import queue
-from ws4py import client as websocket
-
-if hasattr(ssl, 'SSLContext'):
-    # For Python >= 2.7.9 and Python 3.x
-    USE_STDLIB_SSL = True
-else:
-    # For Python 2.6 and <= 2.7.8
-    USE_STDLIB_SSL = False
-
-if not USE_STDLIB_SSL:
-    import OpenSSL.SSL
-
-# Detect SSL tls version
-if hasattr(ssl, 'PROTOCOL_TLSv1_2'):
-    DEFAULT_TLS_VERSION = ssl.PROTOCOL_TLSv1_2
-else:
-    DEFAULT_TLS_VERSION = OpenSSL.SSL.TLSv1_2_METHOD
-
-
-class UnixHTTPConnection(http_client.HTTPConnection):
-
-    def __init__(self, path, host='localhost', port=None, strict=None,
-                 timeout=None):
-        if six.PY34:
-            http_client.HTTPConnection.__init__(self, host, port=port,
-                                                timeout=timeout)
-        else:
-            http_client.HTTPConnection.__init__(self, host, port=port,
-                                                strict=strict,
-                                                timeout=timeout)
-
-        self.path = path
-
-    def connect(self):
-        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        sock.connect(self.path)
-        self.sock = sock
-
-
-class HTTPSConnection(http_client.HTTPConnection):
-    default_port = 8443
-
-    def __init__(self, *args, **kwargs):
-        http_client.HTTPConnection.__init__(self, *args, **kwargs)
-
-    def connect(self):
-        sock = socket.create_connection((self.host, self.port),
-                                        self.timeout, self.source_address)
-        if self._tunnel_host:
-            self.sock = sock
-            self._tunnel()
-
-        (cert_file, key_file) = self._get_ssl_certs()
-        self.sock = ssl.wrap_socket(sock, certfile=cert_file,
-                                    keyfile=key_file,
-                                    ssl_version=DEFAULT_TLS_VERSION)
-
-    @staticmethod
-    def _get_ssl_certs():
-        return (os.path.join(os.environ['HOME'], '.config/lxc/client.crt'),
-                os.path.join(os.environ['HOME'], '.config/lxc/client.key'))
-
-
-_LXDResponse = namedtuple('LXDResponse', ['status', 'body', 'json'])
-
-
-class WebSocketClient(websocket.WebSocketBaseClient):
-    def __init__(self, url, protocols=None, extensions=None, ssl_options=None,
-                 headers=None):
-        """WebSocket client that executes into a eventlet green thread."""
-        websocket.WebSocketBaseClient.__init__(self, url, protocols,
-                                               extensions,
-                                               ssl_options=ssl_options,
-                                               headers=headers)
-        self._th = threading.Thread(target=self.run, name='WebSocketClient')
-        self._th.daemon = True
-
-        self.messages = queue.Queue()
-
-    def handshake_ok(self):
-        """Starts the client's thread."""
-        self._th.start()
-
-    def received_message(self, message):
-        """Override the base class to store the incoming message."""
-        self.messages.put(copy.deepcopy(message))
-
-    def closed(self, code, reason=None):
-        # When the connection is closed, put a StopIteration
-        # on the message queue to signal there's nothing left
-        # to wait for
-        self.messages.put(StopIteration)
-
-    def receive(self):
-        # If the websocket was terminated and there are no messages
-        # left in the queue, return None immediately otherwise the client
-        # will block forever
-        if self.terminated and self.messages.empty():
-            return None
-        message = self.messages.get()
-        if message is StopIteration:
-            return None
-        return message
-
-
-class LXDConnection(object):
-
-    def __init__(self, host=None, port=8443):
-        if host:
-            self.host = host
-            self.port = port
-            self.unix_socket = None
-        else:
-            if 'LXD_DIR' in os.environ:
-                self.unix_socket = os.path.join(os.environ['LXD_DIR'],
-                                                'unix.socket')
-            else:
-                self.unix_socket = '/var/lib/lxd/unix.socket'
-            self.host, self.port = None, None
-        self.connection = None
-
-    def _request(self, *args, **kwargs):
-        if self.connection is None:
-            self.connection = self.get_connection()
-        self.connection.request(*args, **kwargs)
-        response = self.connection.getresponse()
-
-        status = response.status
-        raw_body = response.read()
-        try:
-            if six.PY34:
-                body = json.loads(raw_body.decode())
-            else:
-                body = json.loads(raw_body)
-        except ValueError:
-            body = None
-
-        return _LXDResponse(status, raw_body, body)
-
-    def get_connection(self):
-        if self.host:
-            return HTTPSConnection(self.host, self.port)
-        return UnixHTTPConnection(self.unix_socket)
-
-    def get_object(self, *args, **kwargs):
-        response = self._request(*args, **kwargs)
-
-        if not response.json:
-            raise exceptions.PyLXDException('Null Data')
-        elif response.status == 200 or (
-                response.status == 202 and
-                response.json.get('status_code') == 100):
-            return response.status, response.json
-        else:
-            utils.get_lxd_error(response.status, response.json)
-
-    def get_status(self, *args, **kwargs):
-        response = self._request(*args, **kwargs)
-
-        if not response.json:
-            raise exceptions.PyLXDException('Null Data')
-        elif response.json.get('error'):
-            utils.get_lxd_error(response.status, response.json)
-        elif response.status == 200 or (
-                response.status == 202 and
-                response.json.get('status_code') == 100):
-            return True
-        return False
-
-    def get_raw(self, *args, **kwargs):
-        response = self._request(*args, **kwargs)
-
-        if not response.body:
-            raise exceptions.PyLXDException('Null Body')
-        elif response.status == 200:
-            return response.body
-        else:
-            raise exceptions.PyLXDException('Failed to get raw response')
-
-    def get_ws(self, path):
-        if self.unix_socket:
-            connection_string = 'ws+unix://%s' % self.unix_socket
-        else:
-            connection_string = (
-                'wss://%(host)s:%(port)s' % {'host': self.host,
-                                             'port': self.port}
-            )
-
-        ws = WebSocketClient(connection_string)
-        ws.resource = path
-        ws.connect()
-
-        return ws
diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 8ff8fbb..910a870 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -15,7 +15,7 @@
 import warnings
 
 from pylxd.deprecated import certificate
-from pylxd import connection
+from pylxd.deprecated import connection
 from pylxd.deprecated import container
 from pylxd import hosts
 from pylxd import image
diff --git a/pylxd/deprecated/base.py b/pylxd/deprecated/base.py
index 689e80e..b2b5802 100644
--- a/pylxd/deprecated/base.py
+++ b/pylxd/deprecated/base.py
@@ -13,7 +13,7 @@
 #    under the License.
 from __future__ import print_function
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 
 class LXDBase(object):
diff --git a/pylxd/deprecated/connection.py b/pylxd/deprecated/connection.py
new file mode 100644
index 0000000..c1b9ea1
--- /dev/null
+++ b/pylxd/deprecated/connection.py
@@ -0,0 +1,222 @@
+# Copyright (c) 2015 Canonical Ltd
+# Copyright (c) 2015 Mirantis inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from collections import namedtuple
+import copy
+import json
+import os
+import six
+import socket
+import ssl
+import threading
+
+
+from pylxd import exceptions
+from pylxd import utils
+from six.moves import http_client
+from six.moves import queue
+from ws4py import client as websocket
+
+if hasattr(ssl, 'SSLContext'):
+    # For Python >= 2.7.9 and Python 3.x
+    USE_STDLIB_SSL = True
+else:
+    # For Python 2.6 and <= 2.7.8
+    USE_STDLIB_SSL = False
+
+if not USE_STDLIB_SSL:
+    import OpenSSL.SSL
+
+# Detect SSL tls version
+if hasattr(ssl, 'PROTOCOL_TLSv1_2'):
+    DEFAULT_TLS_VERSION = ssl.PROTOCOL_TLSv1_2
+else:
+    DEFAULT_TLS_VERSION = OpenSSL.SSL.TLSv1_2_METHOD
+
+
+class UnixHTTPConnection(http_client.HTTPConnection):
+
+    def __init__(self, path, host='localhost', port=None, strict=None,
+                 timeout=None):
+        if six.PY34:
+            http_client.HTTPConnection.__init__(self, host, port=port,
+                                                timeout=timeout)
+        else:
+            http_client.HTTPConnection.__init__(self, host, port=port,
+                                                strict=strict,
+                                                timeout=timeout)
+
+        self.path = path
+
+    def connect(self):
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        sock.connect(self.path)
+        self.sock = sock
+
+
+class HTTPSConnection(http_client.HTTPConnection):
+    default_port = 8443
+
+    def __init__(self, *args, **kwargs):
+        http_client.HTTPConnection.__init__(self, *args, **kwargs)
+
+    def connect(self):
+        sock = socket.create_connection((self.host, self.port),
+                                        self.timeout, self.source_address)
+        if self._tunnel_host:
+            self.sock = sock
+            self._tunnel()
+
+        (cert_file, key_file) = self._get_ssl_certs()
+        self.sock = ssl.wrap_socket(sock, certfile=cert_file,
+                                    keyfile=key_file,
+                                    ssl_version=DEFAULT_TLS_VERSION)
+
+    @staticmethod
+    def _get_ssl_certs():
+        return (os.path.join(os.environ['HOME'], '.config/lxc/client.crt'),
+                os.path.join(os.environ['HOME'], '.config/lxc/client.key'))
+
+
+_LXDResponse = namedtuple('LXDResponse', ['status', 'body', 'json'])
+
+
+class WebSocketClient(websocket.WebSocketBaseClient):
+    def __init__(self, url, protocols=None, extensions=None, ssl_options=None,
+                 headers=None):
+        """WebSocket client that executes into a eventlet green thread."""
+        websocket.WebSocketBaseClient.__init__(self, url, protocols,
+                                               extensions,
+                                               ssl_options=ssl_options,
+                                               headers=headers)
+        self._th = threading.Thread(target=self.run, name='WebSocketClient')
+        self._th.daemon = True
+
+        self.messages = queue.Queue()
+
+    def handshake_ok(self):
+        """Starts the client's thread."""
+        self._th.start()
+
+    def received_message(self, message):
+        """Override the base class to store the incoming message."""
+        self.messages.put(copy.deepcopy(message))
+
+    def closed(self, code, reason=None):
+        # When the connection is closed, put a StopIteration
+        # on the message queue to signal there's nothing left
+        # to wait for
+        self.messages.put(StopIteration)
+
+    def receive(self):
+        # If the websocket was terminated and there are no messages
+        # left in the queue, return None immediately otherwise the client
+        # will block forever
+        if self.terminated and self.messages.empty():
+            return None
+        message = self.messages.get()
+        if message is StopIteration:
+            return None
+        return message
+
+
+class LXDConnection(object):
+
+    def __init__(self, host=None, port=8443):
+        if host:
+            self.host = host
+            self.port = port
+            self.unix_socket = None
+        else:
+            if 'LXD_DIR' in os.environ:
+                self.unix_socket = os.path.join(os.environ['LXD_DIR'],
+                                                'unix.socket')
+            else:
+                self.unix_socket = '/var/lib/lxd/unix.socket'
+            self.host, self.port = None, None
+        self.connection = None
+
+    def _request(self, *args, **kwargs):
+        if self.connection is None:
+            self.connection = self.get_connection()
+        self.connection.request(*args, **kwargs)
+        response = self.connection.getresponse()
+
+        status = response.status
+        raw_body = response.read()
+        try:
+            if six.PY34:
+                body = json.loads(raw_body.decode())
+            else:
+                body = json.loads(raw_body)
+        except ValueError:
+            body = None
+
+        return _LXDResponse(status, raw_body, body)
+
+    def get_connection(self):
+        if self.host:
+            return HTTPSConnection(self.host, self.port)
+        return UnixHTTPConnection(self.unix_socket)
+
+    def get_object(self, *args, **kwargs):
+        response = self._request(*args, **kwargs)
+
+        if not response.json:
+            raise exceptions.PyLXDException('Null Data')
+        elif response.status == 200 or (
+                response.status == 202 and
+                response.json.get('status_code') == 100):
+            return response.status, response.json
+        else:
+            utils.get_lxd_error(response.status, response.json)
+
+    def get_status(self, *args, **kwargs):
+        response = self._request(*args, **kwargs)
+
+        if not response.json:
+            raise exceptions.PyLXDException('Null Data')
+        elif response.json.get('error'):
+            utils.get_lxd_error(response.status, response.json)
+        elif response.status == 200 or (
+                response.status == 202 and
+                response.json.get('status_code') == 100):
+            return True
+        return False
+
+    def get_raw(self, *args, **kwargs):
+        response = self._request(*args, **kwargs)
+
+        if not response.body:
+            raise exceptions.PyLXDException('Null Body')
+        elif response.status == 200:
+            return response.body
+        else:
+            raise exceptions.PyLXDException('Failed to get raw response')
+
+    def get_ws(self, path):
+        if self.unix_socket:
+            connection_string = 'ws+unix://%s' % self.unix_socket
+        else:
+            connection_string = (
+                'wss://%(host)s:%(port)s' % {'host': self.host,
+                                             'port': self.port}
+            )
+
+        ws = WebSocketClient(connection_string)
+        ws.resource = path
+        ws.connect()
+
+        return ws
diff --git a/pylxd/image.py b/pylxd/image.py
index b9a3c21..a2cb19e 100644
--- a/pylxd/image.py
+++ b/pylxd/image.py
@@ -18,7 +18,7 @@
 from six.moves import urllib
 
 from pylxd.deprecated import base
-from pylxd import connection
+from pylxd.deprecated import connection
 from pylxd import exceptions
 from pylxd import mixin
 from pylxd.operation import Operation
diff --git a/pylxd/tests/test_certificate.py b/pylxd/tests/test_certificate.py
index 60da277..090944b 100644
--- a/pylxd/tests/test_certificate.py
+++ b/pylxd/tests/test_certificate.py
@@ -16,7 +16,7 @@
 import json
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_connection.py b/pylxd/tests/test_connection.py
index 5fd8a70..1bbfdcf 100644
--- a/pylxd/tests/test_connection.py
+++ b/pylxd/tests/test_connection.py
@@ -21,7 +21,7 @@
 import socket
 import unittest
 
-from pylxd import connection
+from pylxd.deprecated import connection
 from pylxd import exceptions
 from pylxd.tests import annotated_data
 
@@ -80,8 +80,8 @@ def test_https_proxy_connection(self, ms, ml):
                 keyfile='/home/foo/.config/lxc/client.key',
                 ssl_version=connection.DEFAULT_TLS_VERSION)
 
-    @mock.patch('pylxd.connection.HTTPSConnection')
-    @mock.patch('pylxd.connection.UnixHTTPConnection')
+    @mock.patch('pylxd.deprecated.connection.HTTPSConnection')
+    @mock.patch('pylxd.deprecated.connection.UnixHTTPConnection')
     @annotated_data(
         ('unix', (None,), {}, '/var/lib/lxd/unix.socket'),
         ('unix_path', (None,),
@@ -112,7 +112,7 @@ def __init__(self, status, data):
 
 
 @ddt
- at mock.patch('pylxd.connection.LXDConnection.get_connection')
+ at mock.patch('pylxd.deprecated.connection.LXDConnection.get_connection')
 class LXDConnectionTest(unittest.TestCase):
 
     def setUp(self):
@@ -159,7 +159,7 @@ def test_get_raw(self, tag, effect, result, mg):
         else:
             self.assertEqual(result, self.conn.get_raw())
 
-    @mock.patch('pylxd.connection.WebSocketClient')
+    @mock.patch('pylxd.deprecated.connection.WebSocketClient')
     @annotated_data(
         ('fake_host', 'wss://fake_host:8443'),
         (None, 'ws+unix:///var/lib/lxd/unix.socket')
diff --git a/pylxd/tests/test_container.py b/pylxd/tests/test_container.py
index c7e1a9f..0385300 100644
--- a/pylxd/tests/test_container.py
+++ b/pylxd/tests/test_container.py
@@ -18,7 +18,7 @@
 import mock
 import tempfile
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_host.py b/pylxd/tests/test_host.py
index b7dbb6e..2002e57 100644
--- a/pylxd/tests/test_host.py
+++ b/pylxd/tests/test_host.py
@@ -16,7 +16,7 @@
 from ddt import ddt
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 from pylxd import exceptions
 
 from pylxd.tests import annotated_data
diff --git a/pylxd/tests/test_image.py b/pylxd/tests/test_image.py
index 4223f6b..4848c9b 100644
--- a/pylxd/tests/test_image.py
+++ b/pylxd/tests/test_image.py
@@ -19,7 +19,7 @@
 from six.moves import cStringIO
 import unittest
 
-from pylxd import connection
+from pylxd.deprecated import connection
 from pylxd import exceptions
 from pylxd import image
 
diff --git a/pylxd/tests/test_image_alias.py b/pylxd/tests/test_image_alias.py
index 5421461..bccc44c 100644
--- a/pylxd/tests/test_image_alias.py
+++ b/pylxd/tests/test_image_alias.py
@@ -16,7 +16,7 @@
 from ddt import ddt
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_network.py b/pylxd/tests/test_network.py
index 9a40754..65efdb6 100644
--- a/pylxd/tests/test_network.py
+++ b/pylxd/tests/test_network.py
@@ -15,7 +15,7 @@
 from ddt import ddt
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_operation.py b/pylxd/tests/test_operation.py
index 8c7a5dd..233bb0b 100644
--- a/pylxd/tests/test_operation.py
+++ b/pylxd/tests/test_operation.py
@@ -16,7 +16,7 @@
 from ddt import ddt
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_profiles.py b/pylxd/tests/test_profiles.py
index 6aa4743..1844986 100644
--- a/pylxd/tests/test_profiles.py
+++ b/pylxd/tests/test_profiles.py
@@ -16,7 +16,7 @@
 from ddt import ddt
 import mock
 
-from pylxd import connection
+from pylxd.deprecated import connection
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api

From 42fd3ca3499cdebfe72e01e589973ce092dd5f94 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:48:21 -0700
Subject: [PATCH 07/15] Move pylxd.utils to pylxd.deprecated.utils

---
 pylxd/deprecated/connection.py |  2 +-
 pylxd/deprecated/utils.py      | 29 +++++++++++++++++++++++++++++
 pylxd/utils.py                 | 29 -----------------------------
 3 files changed, 30 insertions(+), 30 deletions(-)
 create mode 100644 pylxd/deprecated/utils.py
 delete mode 100644 pylxd/utils.py

diff --git a/pylxd/deprecated/connection.py b/pylxd/deprecated/connection.py
index c1b9ea1..c38cf7b 100644
--- a/pylxd/deprecated/connection.py
+++ b/pylxd/deprecated/connection.py
@@ -24,7 +24,7 @@
 
 
 from pylxd import exceptions
-from pylxd import utils
+from pylxd.deprecated import utils
 from six.moves import http_client
 from six.moves import queue
 from ws4py import client as websocket
diff --git a/pylxd/deprecated/utils.py b/pylxd/deprecated/utils.py
new file mode 100644
index 0000000..4ea2841
--- /dev/null
+++ b/pylxd/deprecated/utils.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from pylxd import exceptions
+
+
+def wait_for_container(name, timeout):
+    pass
+
+
+def block_container():
+    pass
+
+
+def get_lxd_error(state, data):
+    status_code = data.get('error_code')
+    error = data.get('error')
+    raise exceptions.APIError(error, status_code)
diff --git a/pylxd/utils.py b/pylxd/utils.py
deleted file mode 100644
index 4ea2841..0000000
--- a/pylxd/utils.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from pylxd import exceptions
-
-
-def wait_for_container(name, timeout):
-    pass
-
-
-def block_container():
-    pass
-
-
-def get_lxd_error(state, data):
-    status_code = data.get('error_code')
-    error = data.get('error')
-    raise exceptions.APIError(error, status_code)

From 690b8a4ea685ae3196abe4b7f0ca037823ddc649 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:55:02 -0700
Subject: [PATCH 08/15] Move pylxd.exceptions to pylxd.deprecated.exceptions

---
 pylxd/deprecated/connection.py |  6 +++---
 pylxd/deprecated/container.py  |  2 +-
 pylxd/deprecated/exceptions.py | 46 ++++++++++++++++++++++++++++++++++++++++++
 pylxd/deprecated/utils.py      |  2 +-
 pylxd/exceptions.py            | 46 ------------------------------------------
 pylxd/hosts.py                 |  2 +-
 pylxd/image.py                 |  2 +-
 pylxd/tests/test_connection.py |  2 +-
 pylxd/tests/test_host.py       |  2 +-
 pylxd/tests/test_image.py      |  2 +-
 10 files changed, 56 insertions(+), 56 deletions(-)
 create mode 100644 pylxd/deprecated/exceptions.py
 delete mode 100644 pylxd/exceptions.py

diff --git a/pylxd/deprecated/connection.py b/pylxd/deprecated/connection.py
index c38cf7b..5ef884e 100644
--- a/pylxd/deprecated/connection.py
+++ b/pylxd/deprecated/connection.py
@@ -22,13 +22,13 @@
 import ssl
 import threading
 
-
-from pylxd import exceptions
-from pylxd.deprecated import utils
 from six.moves import http_client
 from six.moves import queue
 from ws4py import client as websocket
 
+from pylxd.deprecated import exceptions
+from pylxd.deprecated import utils
+
 if hasattr(ssl, 'SSLContext'):
     # For Python >= 2.7.9 and Python 3.x
     USE_STDLIB_SSL = True
diff --git a/pylxd/deprecated/container.py b/pylxd/deprecated/container.py
index 037ebdd..19bf4b7 100644
--- a/pylxd/deprecated/container.py
+++ b/pylxd/deprecated/container.py
@@ -15,7 +15,7 @@
 import json
 
 from pylxd.deprecated import base
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 
 
 class LXDContainer(base.LXDBase):
diff --git a/pylxd/deprecated/exceptions.py b/pylxd/deprecated/exceptions.py
new file mode 100644
index 0000000..6726bca
--- /dev/null
+++ b/pylxd/deprecated/exceptions.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+
+class PyLXDException(Exception):
+    pass
+
+
+class ContainerUnDefined(PyLXDException):
+    pass
+
+
+class UntrustedHost(PyLXDException):
+    pass
+
+
+class ContainerProfileCreateFail(PyLXDException):
+    pass
+
+
+class ContainerProfileDeleteFail(PyLXDException):
+    pass
+
+
+class ImageInvalidSize(PyLXDException):
+    pass
+
+
+class APIError(PyLXDException):
+
+    def __init__(self, error, status_code):
+        msg = 'Error %s - %s.' % (status_code, error)
+        super(APIError, self).__init__(msg)
+        self.status_code = status_code
+        self.error = error
diff --git a/pylxd/deprecated/utils.py b/pylxd/deprecated/utils.py
index 4ea2841..b6c2585 100644
--- a/pylxd/deprecated/utils.py
+++ b/pylxd/deprecated/utils.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 
 
 def wait_for_container(name, timeout):
diff --git a/pylxd/exceptions.py b/pylxd/exceptions.py
deleted file mode 100644
index 6726bca..0000000
--- a/pylxd/exceptions.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-
-class PyLXDException(Exception):
-    pass
-
-
-class ContainerUnDefined(PyLXDException):
-    pass
-
-
-class UntrustedHost(PyLXDException):
-    pass
-
-
-class ContainerProfileCreateFail(PyLXDException):
-    pass
-
-
-class ContainerProfileDeleteFail(PyLXDException):
-    pass
-
-
-class ImageInvalidSize(PyLXDException):
-    pass
-
-
-class APIError(PyLXDException):
-
-    def __init__(self, error, status_code):
-        msg = 'Error %s - %s.' % (status_code, error)
-        super(APIError, self).__init__(msg)
-        self.status_code = status_code
-        self.error = error
diff --git a/pylxd/hosts.py b/pylxd/hosts.py
index e882bff..8e61894 100644
--- a/pylxd/hosts.py
+++ b/pylxd/hosts.py
@@ -14,7 +14,7 @@
 from __future__ import print_function
 
 from pylxd.deprecated import base
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 
 
 class LXDHost(base.LXDBase):
diff --git a/pylxd/image.py b/pylxd/image.py
index a2cb19e..8a3e85c 100644
--- a/pylxd/image.py
+++ b/pylxd/image.py
@@ -19,7 +19,7 @@
 
 from pylxd.deprecated import base
 from pylxd.deprecated import connection
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 from pylxd import mixin
 from pylxd.operation import Operation
 
diff --git a/pylxd/tests/test_connection.py b/pylxd/tests/test_connection.py
index 1bbfdcf..50e8ffd 100644
--- a/pylxd/tests/test_connection.py
+++ b/pylxd/tests/test_connection.py
@@ -22,7 +22,7 @@
 import unittest
 
 from pylxd.deprecated import connection
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 from pylxd.tests import annotated_data
 
 if six.PY34:
diff --git a/pylxd/tests/test_host.py b/pylxd/tests/test_host.py
index 2002e57..80e2ad4 100644
--- a/pylxd/tests/test_host.py
+++ b/pylxd/tests/test_host.py
@@ -17,7 +17,7 @@
 import mock
 
 from pylxd.deprecated import connection
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api
diff --git a/pylxd/tests/test_image.py b/pylxd/tests/test_image.py
index 4848c9b..69004f6 100644
--- a/pylxd/tests/test_image.py
+++ b/pylxd/tests/test_image.py
@@ -20,7 +20,7 @@
 import unittest
 
 from pylxd.deprecated import connection
-from pylxd import exceptions
+from pylxd.deprecated import exceptions
 from pylxd import image
 
 from pylxd.tests import annotated_data

From 8fa94f993d1b64dcea46be8a76717fa235145f45 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:57:14 -0700
Subject: [PATCH 09/15] Move pylxd.hosts to pylxd.deprecated.hosts

---
 pylxd/deprecated/api.py   |   2 +-
 pylxd/deprecated/hosts.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++
 pylxd/hosts.py            | 110 ----------------------------------------------
 3 files changed, 111 insertions(+), 111 deletions(-)
 create mode 100644 pylxd/deprecated/hosts.py
 delete mode 100644 pylxd/hosts.py

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 910a870..0d432ce 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -17,7 +17,7 @@
 from pylxd.deprecated import certificate
 from pylxd.deprecated import connection
 from pylxd.deprecated import container
-from pylxd import hosts
+from pylxd.deprecated import hosts
 from pylxd import image
 from pylxd import network
 from pylxd import operation
diff --git a/pylxd/deprecated/hosts.py b/pylxd/deprecated/hosts.py
new file mode 100644
index 0000000..8e61894
--- /dev/null
+++ b/pylxd/deprecated/hosts.py
@@ -0,0 +1,110 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from __future__ import print_function
+
+from pylxd.deprecated import base
+from pylxd.deprecated import exceptions
+
+
+class LXDHost(base.LXDBase):
+
+    def host_ping(self):
+        try:
+            return self.connection.get_status('GET', '/1.0')
+        except Exception as e:
+            msg = 'LXD service is unavailable. %s' % e
+            raise exceptions.PyLXDException(msg)
+
+    def host_info(self):
+        (state, data) = self.connection.get_object('GET', '/1.0')
+
+        return {
+            'lxd_api_compat_level':
+                self.get_lxd_api_compat(data.get('metadata')),
+            'lxd_trusted_host':
+                self.get_lxd_host_trust(data.get('metadata')),
+            'lxd_backing_fs':
+                self.get_lxd_backing_fs(data.get('metadata')),
+            'lxd_driver':
+                self.get_lxd_driver(data.get('metadata')),
+            'lxd_version':
+                self.get_lxd_version(data.get('metadata')),
+            'lxc_version':
+                self.get_lxc_version(data.get('metadata')),
+            'kernel_version':
+                self.get_kernel_version(data.get('metadata'))
+        }
+
+    def get_lxd_api_compat(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return data['api_compat']
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_lxd_host_trust(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return True if data['auth'] == 'trusted' else False
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_lxd_backing_fs(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return data['environment']['backing_fs']
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_lxd_driver(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return data['environment']['driver']
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_lxc_version(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return data['environment']['lxc_version']
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_lxd_version(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return float(data['environment']['lxd_version'])
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
+
+    def get_kernel_version(self, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object('GET', '/1.0')
+                data = data.get('metadata')
+            return data['environment']['kernel_version']
+        except exceptions.PyLXDException as e:
+            print('Handling run-time error: {}'.format(e))
diff --git a/pylxd/hosts.py b/pylxd/hosts.py
deleted file mode 100644
index 8e61894..0000000
--- a/pylxd/hosts.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-from __future__ import print_function
-
-from pylxd.deprecated import base
-from pylxd.deprecated import exceptions
-
-
-class LXDHost(base.LXDBase):
-
-    def host_ping(self):
-        try:
-            return self.connection.get_status('GET', '/1.0')
-        except Exception as e:
-            msg = 'LXD service is unavailable. %s' % e
-            raise exceptions.PyLXDException(msg)
-
-    def host_info(self):
-        (state, data) = self.connection.get_object('GET', '/1.0')
-
-        return {
-            'lxd_api_compat_level':
-                self.get_lxd_api_compat(data.get('metadata')),
-            'lxd_trusted_host':
-                self.get_lxd_host_trust(data.get('metadata')),
-            'lxd_backing_fs':
-                self.get_lxd_backing_fs(data.get('metadata')),
-            'lxd_driver':
-                self.get_lxd_driver(data.get('metadata')),
-            'lxd_version':
-                self.get_lxd_version(data.get('metadata')),
-            'lxc_version':
-                self.get_lxc_version(data.get('metadata')),
-            'kernel_version':
-                self.get_kernel_version(data.get('metadata'))
-        }
-
-    def get_lxd_api_compat(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return data['api_compat']
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_lxd_host_trust(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return True if data['auth'] == 'trusted' else False
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_lxd_backing_fs(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return data['environment']['backing_fs']
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_lxd_driver(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return data['environment']['driver']
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_lxc_version(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return data['environment']['lxc_version']
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_lxd_version(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return float(data['environment']['lxd_version'])
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))
-
-    def get_kernel_version(self, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object('GET', '/1.0')
-                data = data.get('metadata')
-            return data['environment']['kernel_version']
-        except exceptions.PyLXDException as e:
-            print('Handling run-time error: {}'.format(e))

From 57e1e681d692a2a4a119bcff9583199e1a3a63bf Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 19:58:44 -0700
Subject: [PATCH 10/15] Move pylxd.network import pylxd.deprecated.network

---
 pylxd/deprecated/api.py     |  2 +-
 pylxd/deprecated/network.py | 59 +++++++++++++++++++++++++++++++++++++++++++++
 pylxd/network.py            | 59 ---------------------------------------------
 3 files changed, 60 insertions(+), 60 deletions(-)
 create mode 100644 pylxd/deprecated/network.py
 delete mode 100644 pylxd/network.py

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 0d432ce..bf1ddc1 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -19,7 +19,7 @@
 from pylxd.deprecated import container
 from pylxd.deprecated import hosts
 from pylxd import image
-from pylxd import network
+from pylxd.deprecated import network
 from pylxd import operation
 from pylxd import profiles
 
diff --git a/pylxd/deprecated/network.py b/pylxd/deprecated/network.py
new file mode 100644
index 0000000..3eff79e
--- /dev/null
+++ b/pylxd/deprecated/network.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from pylxd.deprecated import base
+
+
+class LXDNetwork(base.LXDBase):
+
+    def network_list(self):
+        (state, data) = self.connection.get_object('GET', '/1.0/networks')
+        return [network.split('/1.0/networks/')[-1]
+                for network in data['metadata']]
+
+    def network_show(self, network):
+        '''Show details of the LXD network'''
+        (state, data) = self.connection.get_object('GET', '/1.0/networks/%s'
+                                                   % network)
+        return {
+            'network_name':
+                self.show_network_name(network, data.get('metadata')),
+            'network_type':
+                self.show_network_type(network, data.get('metadata')),
+            'network_members':
+                self.show_network_members(network, data.get('metadata'))
+        }
+
+    def show_network_name(self, network, data):
+        '''Show the LXD network name'''
+        if data is None:
+            (state, data) = self.connection.get_object(
+                'GET', '/1.0/networks/%s' % network)
+            data = data.get('metadata')
+        return data['name']
+
+    def show_network_type(self, network, data):
+        if data is None:
+            (state, data) = self.connection.get_object(
+                'GET', '/1.0/networks/%s' % network)
+            data = data.get('metadata')
+        return data['type']
+
+    def show_network_members(self, network, data):
+        if data is None:
+            (state, data) = self.connection.get_object(
+                'GET', '/1.0/networks/%s' % network)
+            data = data.get('metadata')
+        return [network_members.split('/1.0/networks/')[-1]
+                for network_members in data['members']]
diff --git a/pylxd/network.py b/pylxd/network.py
deleted file mode 100644
index 3eff79e..0000000
--- a/pylxd/network.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from pylxd.deprecated import base
-
-
-class LXDNetwork(base.LXDBase):
-
-    def network_list(self):
-        (state, data) = self.connection.get_object('GET', '/1.0/networks')
-        return [network.split('/1.0/networks/')[-1]
-                for network in data['metadata']]
-
-    def network_show(self, network):
-        '''Show details of the LXD network'''
-        (state, data) = self.connection.get_object('GET', '/1.0/networks/%s'
-                                                   % network)
-        return {
-            'network_name':
-                self.show_network_name(network, data.get('metadata')),
-            'network_type':
-                self.show_network_type(network, data.get('metadata')),
-            'network_members':
-                self.show_network_members(network, data.get('metadata'))
-        }
-
-    def show_network_name(self, network, data):
-        '''Show the LXD network name'''
-        if data is None:
-            (state, data) = self.connection.get_object(
-                'GET', '/1.0/networks/%s' % network)
-            data = data.get('metadata')
-        return data['name']
-
-    def show_network_type(self, network, data):
-        if data is None:
-            (state, data) = self.connection.get_object(
-                'GET', '/1.0/networks/%s' % network)
-            data = data.get('metadata')
-        return data['type']
-
-    def show_network_members(self, network, data):
-        if data is None:
-            (state, data) = self.connection.get_object(
-                'GET', '/1.0/networks/%s' % network)
-            data = data.get('metadata')
-        return [network_members.split('/1.0/networks/')[-1]
-                for network_members in data['members']]

From f7e25fa48c3e55b5039b66a89ba5f74d61e7974b Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 20:02:26 -0700
Subject: [PATCH 11/15] Move pylxd.image.LXDImage to pylxd.deprecated.image

---
 pylxd/deprecated/api.py   |   2 +-
 pylxd/deprecated/image.py | 244 ++++++++++++++++++++++++++++++++++++++++++++++
 pylxd/image.py            | 231 +------------------------------------------
 pylxd/tests/test_image.py |   2 +-
 4 files changed, 247 insertions(+), 232 deletions(-)
 create mode 100644 pylxd/deprecated/image.py

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index bf1ddc1..48b1518 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -18,7 +18,7 @@
 from pylxd.deprecated import connection
 from pylxd.deprecated import container
 from pylxd.deprecated import hosts
-from pylxd import image
+from pylxd.deprecated import image
 from pylxd.deprecated import network
 from pylxd import operation
 from pylxd import profiles
diff --git a/pylxd/deprecated/image.py b/pylxd/deprecated/image.py
new file mode 100644
index 0000000..acfdbca
--- /dev/null
+++ b/pylxd/deprecated/image.py
@@ -0,0 +1,244 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from __future__ import print_function
+import datetime
+import json
+
+from six.moves import urllib
+
+from pylxd.deprecated import base
+from pylxd.deprecated import connection
+from pylxd.deprecated import exceptions
+
+image_architecture = {
+    0: 'Unknown',
+    1: 'i686',
+    2: 'x86_64',
+    3: 'armv7l',
+    4: 'aarch64',
+    5: 'ppc',
+    6: 'ppc64',
+    7: 'ppc64le'
+}
+
+
+class LXDImage(base.LXDBase):
+
+    def __init__(self, conn=None):
+        self.connection = conn or connection.LXDConnection()
+
+    # list images
+    def image_list(self):
+        try:
+            (state, data) = self.connection.get_object('GET', '/1.0/images')
+            return [image.split('/1.0/images/')[-1]
+                    for image in data['metadata']]
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def image_defined(self, image):
+        try:
+            (state, data) = self.connection.get_object('GET', '/1.0/images/%s'
+                                                       % image)
+        except exceptions.APIError as ex:
+            if ex.status_code == 404:
+                return False
+            else:
+                raise
+        else:
+            return True
+
+    def image_list_by_key(self, params):
+        try:
+            (state, data) = self.connection.get_object(
+                'GET', '/1.0/images', urllib.parse.urlencode(params))
+            return [image.split('/1.0/images/')[-1]
+                    for image in data['metadata']]
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    # image info
+    def image_info(self, image):
+        try:
+            (state, data) = self.connection.get_object('GET', '/1.0/images/%s'
+                                                       % image)
+            image = {
+                'image_upload_date': self.get_image_date(image,
+                                                         data.get('metadata'),
+                                                         'uploaded_at'),
+                'image_created_date': self.get_image_date(image,
+                                                          data.get('metadata'),
+                                                          'created_at'),
+                'image_expires_date': self.get_image_date(image,
+                                                          data.get('metadata'),
+                                                          'expires_at'),
+                'image_public': self.get_image_permission(
+                    image,
+                    data.get('metadata')),
+                'image_size': '%sMB' % self.get_image_size(
+                    image,
+                    data.get('metadata')),
+                'image_fingerprint': self.get_image_fingerprint(
+                    image,
+                    data.get('metadata')),
+                'image_architecture': self.get_image_architecture(
+                    image,
+                    data.get('metadata')),
+            }
+
+            return image
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def get_image_date(self, image, data, key):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object(
+                    'GET', '/1.0/images/%s' % image)
+                data = data.get('metadata')
+            if data[key] != 0:
+                return datetime.datetime.fromtimestamp(
+                    data[key]).strftime('%Y-%m-%d %H:%M:%S')
+            else:
+                return 'Unknown'
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def get_image_permission(self, image, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object(
+                    'GET', '/1.0/images/%s' % image)
+                data = data.get('metadata')
+            return True if data['public'] == 1 else False
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def get_image_size(self, image, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object(
+                    'GET', '/1.0/images/%s' % image)
+                data = data.get('metadata')
+            image_size = data['size']
+            if image_size <= 0:
+                raise exceptions.ImageInvalidSize()
+            return image_size // 1024 ** 2
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def get_image_fingerprint(self, image, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object(
+                    'GET', '/1.0/images/%s' % image)
+                data = data.get('metadata')
+            return data['fingerprint']
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    def get_image_architecture(self, image, data):
+        try:
+            if data is None:
+                (state, data) = self.connection.get_object(
+                    'GET', '/1.0/images/%s' % image)
+                data = data.get('metadata')
+            return image_architecture[data['architecture']]
+        except Exception as e:
+            print("Unable to fetch image info - {}".format(e))
+            raise
+
+    # image operations
+    def image_upload(self, path=None, data=None, headers={}):
+        data = data or open(path, 'rb').read()
+        try:
+            return self.connection.get_object('POST', '/1.0/images',
+                                              data, headers)
+        except Exception as e:
+            print("Unable to upload image - {}".format(e))
+            raise
+
+    def image_delete(self, image):
+        try:
+            return self.connection.get_status('DELETE', '/1.0/images/%s'
+                                              % image)
+        except Exception as e:
+            print("Unable to delete image - {}".format(e))
+            raise
+
+    def image_export(self, image):
+        try:
+            return self.connection.get_raw('GET', '/1.0/images/%s/export'
+                                           % image)
+        except Exception as e:
+            print("Unable to export image - {}".format(e))
+            raise
+
+    def image_update(self, image, data):
+        try:
+            return self.connection.get_status('PUT', '/1.0/images/%s' % image,
+                                              json.dumps(data))
+        except Exception as e:
+            print("Unable to update image - {}".format(e))
+            raise
+
+    def image_rename(self, image, data):
+        try:
+            return self.connection.get_status('POST', '/1.0/images/%s' % image,
+                                              json.dumps(data))
+        except Exception as e:
+            print("Unable to rename image - {}".format(e))
+            raise
+
+
+class LXDAlias(base.LXDBase):
+
+    def alias_list(self):
+        (state, data) = self.connection.get_object(
+            'GET', '/1.0/images/aliases')
+        return [alias.split('/1.0/images/aliases/')[-1]
+                for alias in data['metadata']]
+
+    def alias_defined(self, alias):
+        return self.connection.get_status('GET', '/1.0/images/aliases/%s'
+                                          % alias)
+
+    def alias_show(self, alias):
+        return self.connection.get_object('GET', '/1.0/images/aliases/%s'
+                                          % alias)
+
+    def alias_update(self, alias, data):
+        return self.connection.get_status('PUT',
+                                          '/1.0/images/aliases/%s' % alias,
+                                          json.dumps(data))
+
+    def alias_rename(self, alias, data):
+        return self.connection.get_status('POST',
+                                          '/1.0/images/aliases/%s' % alias,
+                                          json.dumps(data))
+
+    def alias_create(self, data):
+        return self.connection.get_status('POST', '/1.0/images/aliases',
+                                          json.dumps(data))
+
+    def alias_delete(self, alias):
+        return self.connection.get_status('DELETE', '/1.0/images/aliases/%s'
+                                          % alias)
diff --git a/pylxd/image.py b/pylxd/image.py
index 8a3e85c..31a5257 100644
--- a/pylxd/image.py
+++ b/pylxd/image.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 Canonical Ltd
+# Copyright (c) 2016 Canonical Ltd
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -11,240 +11,11 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-from __future__ import print_function
-import datetime
 import hashlib
-import json
-from six.moves import urllib
 
-from pylxd.deprecated import base
-from pylxd.deprecated import connection
-from pylxd.deprecated import exceptions
 from pylxd import mixin
 from pylxd.operation import Operation
 
-image_architecture = {
-    0: 'Unknown',
-    1: 'i686',
-    2: 'x86_64',
-    3: 'armv7l',
-    4: 'aarch64',
-    5: 'ppc',
-    6: 'ppc64',
-    7: 'ppc64le'
-}
-
-
-class LXDImage(base.LXDBase):
-
-    def __init__(self, conn=None):
-        self.connection = conn or connection.LXDConnection()
-
-    # list images
-    def image_list(self):
-        try:
-            (state, data) = self.connection.get_object('GET', '/1.0/images')
-            return [image.split('/1.0/images/')[-1]
-                    for image in data['metadata']]
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def image_defined(self, image):
-        try:
-            (state, data) = self.connection.get_object('GET', '/1.0/images/%s'
-                                                       % image)
-        except exceptions.APIError as ex:
-            if ex.status_code == 404:
-                return False
-            else:
-                raise
-        else:
-            return True
-
-    def image_list_by_key(self, params):
-        try:
-            (state, data) = self.connection.get_object(
-                'GET', '/1.0/images', urllib.parse.urlencode(params))
-            return [image.split('/1.0/images/')[-1]
-                    for image in data['metadata']]
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    # image info
-    def image_info(self, image):
-        try:
-            (state, data) = self.connection.get_object('GET', '/1.0/images/%s'
-                                                       % image)
-            image = {
-                'image_upload_date': self.get_image_date(image,
-                                                         data.get('metadata'),
-                                                         'uploaded_at'),
-                'image_created_date': self.get_image_date(image,
-                                                          data.get('metadata'),
-                                                          'created_at'),
-                'image_expires_date': self.get_image_date(image,
-                                                          data.get('metadata'),
-                                                          'expires_at'),
-                'image_public': self.get_image_permission(
-                    image,
-                    data.get('metadata')),
-                'image_size': '%sMB' % self.get_image_size(
-                    image,
-                    data.get('metadata')),
-                'image_fingerprint': self.get_image_fingerprint(
-                    image,
-                    data.get('metadata')),
-                'image_architecture': self.get_image_architecture(
-                    image,
-                    data.get('metadata')),
-            }
-
-            return image
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def get_image_date(self, image, data, key):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object(
-                    'GET', '/1.0/images/%s' % image)
-                data = data.get('metadata')
-            if data[key] != 0:
-                return datetime.datetime.fromtimestamp(
-                    data[key]).strftime('%Y-%m-%d %H:%M:%S')
-            else:
-                return 'Unknown'
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def get_image_permission(self, image, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object(
-                    'GET', '/1.0/images/%s' % image)
-                data = data.get('metadata')
-            return True if data['public'] == 1 else False
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def get_image_size(self, image, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object(
-                    'GET', '/1.0/images/%s' % image)
-                data = data.get('metadata')
-            image_size = data['size']
-            if image_size <= 0:
-                raise exceptions.ImageInvalidSize()
-            return image_size // 1024 ** 2
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def get_image_fingerprint(self, image, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object(
-                    'GET', '/1.0/images/%s' % image)
-                data = data.get('metadata')
-            return data['fingerprint']
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    def get_image_architecture(self, image, data):
-        try:
-            if data is None:
-                (state, data) = self.connection.get_object(
-                    'GET', '/1.0/images/%s' % image)
-                data = data.get('metadata')
-            return image_architecture[data['architecture']]
-        except Exception as e:
-            print("Unable to fetch image info - {}".format(e))
-            raise
-
-    # image operations
-    def image_upload(self, path=None, data=None, headers={}):
-        data = data or open(path, 'rb').read()
-        try:
-            return self.connection.get_object('POST', '/1.0/images',
-                                              data, headers)
-        except Exception as e:
-            print("Unable to upload image - {}".format(e))
-            raise
-
-    def image_delete(self, image):
-        try:
-            return self.connection.get_status('DELETE', '/1.0/images/%s'
-                                              % image)
-        except Exception as e:
-            print("Unable to delete image - {}".format(e))
-            raise
-
-    def image_export(self, image):
-        try:
-            return self.connection.get_raw('GET', '/1.0/images/%s/export'
-                                           % image)
-        except Exception as e:
-            print("Unable to export image - {}".format(e))
-            raise
-
-    def image_update(self, image, data):
-        try:
-            return self.connection.get_status('PUT', '/1.0/images/%s' % image,
-                                              json.dumps(data))
-        except Exception as e:
-            print("Unable to update image - {}".format(e))
-            raise
-
-    def image_rename(self, image, data):
-        try:
-            return self.connection.get_status('POST', '/1.0/images/%s' % image,
-                                              json.dumps(data))
-        except Exception as e:
-            print("Unable to rename image - {}".format(e))
-            raise
-
-
-class LXDAlias(base.LXDBase):
-
-    def alias_list(self):
-        (state, data) = self.connection.get_object(
-            'GET', '/1.0/images/aliases')
-        return [alias.split('/1.0/images/aliases/')[-1]
-                for alias in data['metadata']]
-
-    def alias_defined(self, alias):
-        return self.connection.get_status('GET', '/1.0/images/aliases/%s'
-                                          % alias)
-
-    def alias_show(self, alias):
-        return self.connection.get_object('GET', '/1.0/images/aliases/%s'
-                                          % alias)
-
-    def alias_update(self, alias, data):
-        return self.connection.get_status('PUT',
-                                          '/1.0/images/aliases/%s' % alias,
-                                          json.dumps(data))
-
-    def alias_rename(self, alias, data):
-        return self.connection.get_status('POST',
-                                          '/1.0/images/aliases/%s' % alias,
-                                          json.dumps(data))
-
-    def alias_create(self, data):
-        return self.connection.get_status('POST', '/1.0/images/aliases',
-                                          json.dumps(data))
-
-    def alias_delete(self, alias):
-        return self.connection.get_status('DELETE', '/1.0/images/aliases/%s'
-                                          % alias)
-
 
 class Image(mixin.Waitable, mixin.Marshallable):
     """A LXD Image."""
diff --git a/pylxd/tests/test_image.py b/pylxd/tests/test_image.py
index 69004f6..93b33f1 100644
--- a/pylxd/tests/test_image.py
+++ b/pylxd/tests/test_image.py
@@ -21,7 +21,7 @@
 
 from pylxd.deprecated import connection
 from pylxd.deprecated import exceptions
-from pylxd import image
+from pylxd.deprecated import image
 
 from pylxd.tests import annotated_data
 from pylxd.tests import fake_api

From 763d04b3f40f47490419690f8589b2a22523e748 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 20:05:22 -0700
Subject: [PATCH 12/15] Move pylxd.operation.LXDOperation to
 pylxd.deprecated.operation

---
 pylxd/deprecated/api.py       |  2 +-
 pylxd/deprecated/operation.py | 73 +++++++++++++++++++++++++++++++++++++++++++
 pylxd/operation.py            | 63 +------------------------------------
 3 files changed, 75 insertions(+), 63 deletions(-)
 create mode 100644 pylxd/deprecated/operation.py

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 48b1518..5458612 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -20,7 +20,7 @@
 from pylxd.deprecated import hosts
 from pylxd.deprecated import image
 from pylxd.deprecated import network
-from pylxd import operation
+from pylxd.deprecated import operation
 from pylxd import profiles
 
 
diff --git a/pylxd/deprecated/operation.py b/pylxd/deprecated/operation.py
new file mode 100644
index 0000000..48fd81b
--- /dev/null
+++ b/pylxd/deprecated/operation.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from dateutil.parser import parse as parse_date
+
+from pylxd.deprecated import base
+
+
+class LXDOperation(base.LXDBase):
+
+    def operation_list(self):
+        (state, data) = self.connection.get_object('GET', '/1.0/operations')
+        return data['metadata']
+
+    def operation_show(self, operation):
+        (state, data) = self.connection.get_object('GET', operation)
+
+        return {
+            'operation_create_time':
+                self.operation_create_time(operation, data.get('metadata')),
+            'operation_update_time':
+                self.operation_update_time(operation, data.get('metadata')),
+            'operation_status_code':
+                self.operation_status_code(operation, data.get('metadata'))
+        }
+
+    def operation_info(self, operation):
+        return self.connection.get_object('GET', operation)
+
+    def operation_create_time(self, operation, data):
+        if data is None:
+            (state, data) = self.connection.get_object('GET', operation)
+            data = data.get('metadata')
+        return parse_date(data['created_at']).strftime('%Y-%m-%d %H:%M:%S')
+
+    def operation_update_time(self, operation, data):
+        if data is None:
+            (state, data) = self.connection.get_object('GET', operation)
+            data = data.get('metadata')
+        return parse_date(data['updated_at']).strftime('%Y-%m-%d %H:%M:%S')
+
+    def operation_status_code(self, operation, data):
+        if data is None:
+            (state, data) = self.connection.get_object('GET', operation)
+            data = data.get('metadata')
+        return data['status']
+
+    def operation_wait(self, operation, status_code, timeout):
+        if timeout == -1:
+            return self.connection.get_status(
+                'GET', '%s/wait?status_code=%s'
+                % (operation, status_code))
+        else:
+            return self.connection.get_status(
+                'GET', '%s/wait?status_code=%s&timeout=%s'
+                % (operation, status_code, timeout))
+
+    def operation_stream(self, operation, operation_secret):
+        return self.connection.get_ws(
+            '%s/websocket?secret=%s' % (operation, operation_secret))
+
+    def operation_delete(self, operation):
+        return self.connection.get_status('DELETE', operation)
diff --git a/pylxd/operation.py b/pylxd/operation.py
index 27766f6..b5c7d67 100644
--- a/pylxd/operation.py
+++ b/pylxd/operation.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 Canonical Ltd
+# Copyright (c) 2016 Canonical Ltd
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -12,67 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from dateutil.parser import parse as parse_date
-
-from pylxd.deprecated import base
-
-
-class LXDOperation(base.LXDBase):
-
-    def operation_list(self):
-        (state, data) = self.connection.get_object('GET', '/1.0/operations')
-        return data['metadata']
-
-    def operation_show(self, operation):
-        (state, data) = self.connection.get_object('GET', operation)
-
-        return {
-            'operation_create_time':
-                self.operation_create_time(operation, data.get('metadata')),
-            'operation_update_time':
-                self.operation_update_time(operation, data.get('metadata')),
-            'operation_status_code':
-                self.operation_status_code(operation, data.get('metadata'))
-        }
-
-    def operation_info(self, operation):
-        return self.connection.get_object('GET', operation)
-
-    def operation_create_time(self, operation, data):
-        if data is None:
-            (state, data) = self.connection.get_object('GET', operation)
-            data = data.get('metadata')
-        return parse_date(data['created_at']).strftime('%Y-%m-%d %H:%M:%S')
-
-    def operation_update_time(self, operation, data):
-        if data is None:
-            (state, data) = self.connection.get_object('GET', operation)
-            data = data.get('metadata')
-        return parse_date(data['updated_at']).strftime('%Y-%m-%d %H:%M:%S')
-
-    def operation_status_code(self, operation, data):
-        if data is None:
-            (state, data) = self.connection.get_object('GET', operation)
-            data = data.get('metadata')
-        return data['status']
-
-    def operation_wait(self, operation, status_code, timeout):
-        if timeout == -1:
-            return self.connection.get_status(
-                'GET', '%s/wait?status_code=%s'
-                % (operation, status_code))
-        else:
-            return self.connection.get_status(
-                'GET', '%s/wait?status_code=%s&timeout=%s'
-                % (operation, status_code, timeout))
-
-    def operation_stream(self, operation, operation_secret):
-        return self.connection.get_ws(
-            '%s/websocket?secret=%s' % (operation, operation_secret))
-
-    def operation_delete(self, operation):
-        return self.connection.get_status('DELETE', operation)
-
 
 class Operation(object):
     """A LXD operation."""

From 8fdaae803971241008ee657c8d75fc27219d5124 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 20:08:14 -0700
Subject: [PATCH 13/15] Move pylxd.profiles.LXDProfile to
 pylxd.deprecated.profiles

---
 pylxd/deprecated/api.py      |  2 +-
 pylxd/deprecated/profiles.py | 57 ++++++++++++++++++++++++++++++++++++++++++++
 pylxd/profiles.py            | 46 +----------------------------------
 3 files changed, 59 insertions(+), 46 deletions(-)
 create mode 100644 pylxd/deprecated/profiles.py

diff --git a/pylxd/deprecated/api.py b/pylxd/deprecated/api.py
index 5458612..bb0f115 100644
--- a/pylxd/deprecated/api.py
+++ b/pylxd/deprecated/api.py
@@ -21,7 +21,7 @@
 from pylxd.deprecated import image
 from pylxd.deprecated import network
 from pylxd.deprecated import operation
-from pylxd import profiles
+from pylxd.deprecated import profiles
 
 
 class API(object):
diff --git a/pylxd/deprecated/profiles.py b/pylxd/deprecated/profiles.py
new file mode 100644
index 0000000..12c1300
--- /dev/null
+++ b/pylxd/deprecated/profiles.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+import json
+
+from pylxd.deprecated import base
+
+
+class LXDProfile(base.LXDBase):
+
+    def profile_list(self):
+        '''List profiles on the LXD daemon as an array.'''
+        (state, data) = self.connection.get_object('GET', '/1.0/profiles')
+        return [profiles.split('/1.0/profiles/')[-1]
+                for profiles in data['metadata']]
+
+    def profile_create(self, profile):
+        '''Create an LXD Profile'''
+        return self.connection.get_status('POST', '/1.0/profiles',
+                                          json.dumps(profile))
+
+    def profile_show(self, profile):
+        '''Display the LXD profile'''
+        return self.connection.get_object('GET', '/1.0/profiles/%s'
+                                          % profile)
+
+    def profile_defined(self, profile):
+        '''Check for an LXD profile'''
+        return self.connection.get_status('GET', '/1.0/profiles/%s'
+                                          % profile)
+
+    def profile_update(self, profile, config):
+        '''Update the LXD profile (not implemented)'''
+        return self.connection.get_status('PUT', '/1.0/profiles/%s'
+                                          % profile,
+                                          json.dumps(config))
+
+    def profile_rename(self, profile, config):
+        '''Rename the LXD profile'''
+        return self.connection.get_status('POST', '/1.0/profiles/%s'
+                                          % profile,
+                                          json.dumps(config))
+
+    def profile_delete(self, profile):
+        '''Delete the LXD profile'''
+        return self.connection.get_status('DELETE', '/1.0/profiles/%s'
+                                          % profile)
diff --git a/pylxd/profiles.py b/pylxd/profiles.py
index da39c2b..2567dc8 100644
--- a/pylxd/profiles.py
+++ b/pylxd/profiles.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 Canonical Ltd
+# Copyright (c) 2016 Canonical Ltd
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -12,53 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 # XXX: rockstar (15 Feb 2016) - This module should be renamed to 'profile'.
-import json
-
-from pylxd.deprecated import base
 from pylxd import mixin
 
 
-class LXDProfile(base.LXDBase):
-
-    def profile_list(self):
-        '''List profiles on the LXD daemon as an array.'''
-        (state, data) = self.connection.get_object('GET', '/1.0/profiles')
-        return [profiles.split('/1.0/profiles/')[-1]
-                for profiles in data['metadata']]
-
-    def profile_create(self, profile):
-        '''Create an LXD Profile'''
-        return self.connection.get_status('POST', '/1.0/profiles',
-                                          json.dumps(profile))
-
-    def profile_show(self, profile):
-        '''Display the LXD profile'''
-        return self.connection.get_object('GET', '/1.0/profiles/%s'
-                                          % profile)
-
-    def profile_defined(self, profile):
-        '''Check for an LXD profile'''
-        return self.connection.get_status('GET', '/1.0/profiles/%s'
-                                          % profile)
-
-    def profile_update(self, profile, config):
-        '''Update the LXD profile (not implemented)'''
-        return self.connection.get_status('PUT', '/1.0/profiles/%s'
-                                          % profile,
-                                          json.dumps(config))
-
-    def profile_rename(self, profile, config):
-        '''Rename the LXD profile'''
-        return self.connection.get_status('POST', '/1.0/profiles/%s'
-                                          % profile,
-                                          json.dumps(config))
-
-    def profile_delete(self, profile):
-        '''Delete the LXD profile'''
-        return self.connection.get_status('DELETE', '/1.0/profiles/%s'
-                                          % profile)
-
-
 class Profile(mixin.Marshallable):
     """A LXD profile."""
 

From d9664c0e3e074a7975eb5f268f0d1366053da1ce Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 20:15:48 -0700
Subject: [PATCH 14/15] Move pylxd.profiles pylxd.profile

---
 pylxd/client.py   |  2 +-
 pylxd/profile.py  | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 pylxd/profiles.py | 78 -------------------------------------------------------
 3 files changed, 78 insertions(+), 79 deletions(-)
 create mode 100644 pylxd/profile.py
 delete mode 100644 pylxd/profiles.py

diff --git a/pylxd/client.py b/pylxd/client.py
index b2d5fc3..33a0e3d 100644
--- a/pylxd/client.py
+++ b/pylxd/client.py
@@ -21,7 +21,7 @@
 from pylxd.container import Container
 from pylxd.image import Image
 from pylxd.operation import Operation
-from pylxd.profiles import Profile
+from pylxd.profile import Profile
 
 requests_unixsocket.monkeypatch()
 
diff --git a/pylxd/profile.py b/pylxd/profile.py
new file mode 100644
index 0000000..13c3847
--- /dev/null
+++ b/pylxd/profile.py
@@ -0,0 +1,77 @@
+# Copyright (c) 2016 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from pylxd import mixin
+
+
+class Profile(mixin.Marshallable):
+    """A LXD profile."""
+
+    __slots__ = [
+        '_client',
+        'config', 'devices', 'name'
+        ]
+
+    @classmethod
+    def get(cls, client, name):
+        """Get a profile."""
+        response = client.api.profiles[name].get()
+
+        if response.status_code == 404:
+            raise NameError('No profile with name "{}"'.format(name))
+        return cls(_client=client, **response.json()['metadata'])
+
+    @classmethod
+    def all(cls, client):
+        """Get all profiles."""
+        response = client.api.profiles.get()
+
+        profiles = []
+        for url in response.json()['metadata']:
+            name = url.split('/')[-1]
+            profiles.append(cls(_client=client, name=name))
+        return profiles
+
+    @classmethod
+    def create(cls, client, name, config):
+        """Create a profile."""
+        client.api.profiles.post(json={
+            'name': name,
+            'config': config
+            })
+
+        return cls.get(client, name)
+
+    def __init__(self, **kwargs):
+        super(Profile, self).__init__()
+        for key, value in kwargs.iteritems():
+            setattr(self, key, value)
+
+    def update(self):
+        """Update the profile in LXD based on local changes."""
+        marshalled = self.marshall()
+        # The name property cannot be updated.
+        del marshalled['name']
+
+        self._client.api.profiles[self.name].put(json=marshalled)
+
+    def rename(self, new):
+        """Rename the profile."""
+        raise NotImplementedError(
+            'LXD does not currently support renaming profiles')
+        self._client.api.profiles[self.name].post(json={'name': new})
+        self.name = new
+
+    def delete(self):
+        """Delete a profile."""
+        self._client.api.profiles[self.name].delete()
diff --git a/pylxd/profiles.py b/pylxd/profiles.py
deleted file mode 100644
index 2567dc8..0000000
--- a/pylxd/profiles.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright (c) 2016 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-# XXX: rockstar (15 Feb 2016) - This module should be renamed to 'profile'.
-from pylxd import mixin
-
-
-class Profile(mixin.Marshallable):
-    """A LXD profile."""
-
-    __slots__ = [
-        '_client',
-        'config', 'devices', 'name'
-        ]
-
-    @classmethod
-    def get(cls, client, name):
-        """Get a profile."""
-        response = client.api.profiles[name].get()
-
-        if response.status_code == 404:
-            raise NameError('No profile with name "{}"'.format(name))
-        return cls(_client=client, **response.json()['metadata'])
-
-    @classmethod
-    def all(cls, client):
-        """Get all profiles."""
-        response = client.api.profiles.get()
-
-        profiles = []
-        for url in response.json()['metadata']:
-            name = url.split('/')[-1]
-            profiles.append(cls(_client=client, name=name))
-        return profiles
-
-    @classmethod
-    def create(cls, client, name, config):
-        """Create a profile."""
-        client.api.profiles.post(json={
-            'name': name,
-            'config': config
-            })
-
-        return cls.get(client, name)
-
-    def __init__(self, **kwargs):
-        super(Profile, self).__init__()
-        for key, value in kwargs.iteritems():
-            setattr(self, key, value)
-
-    def update(self):
-        """Update the profile in LXD based on local changes."""
-        marshalled = self.marshall()
-        # The name property cannot be updated.
-        del marshalled['name']
-
-        self._client.api.profiles[self.name].put(json=marshalled)
-
-    def rename(self, new):
-        """Rename the profile."""
-        raise NotImplementedError(
-            'LXD does not currently support renaming profiles')
-        self._client.api.profiles[self.name].post(json={'name': new})
-        self.name = new
-
-    def delete(self):
-        """Delete a profile."""
-        self._client.api.profiles[self.name].delete()

From 73b3a6405d6dd13fdf135992f0fc5ebb4e965d6c Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul at eventuallyanyway.com>
Date: Tue, 16 Feb 2016 20:22:11 -0700
Subject: [PATCH 15/15] Move pylxd.tests to pylxd.deprecated.tests

---
 pylxd/deprecated/tests/__init__.py         |  40 +++++
 pylxd/deprecated/tests/fake_api.py         | 272 +++++++++++++++++++++++++++++
 pylxd/deprecated/tests/test_certificate.py |  57 ++++++
 pylxd/deprecated/tests/test_client.py      |  90 ++++++++++
 pylxd/deprecated/tests/test_connection.py  | 172 ++++++++++++++++++
 pylxd/deprecated/tests/test_container.py   | 222 +++++++++++++++++++++++
 pylxd/deprecated/tests/test_host.py        |  82 +++++++++
 pylxd/deprecated/tests/test_image.py       | 241 +++++++++++++++++++++++++
 pylxd/deprecated/tests/test_image_alias.py |  66 +++++++
 pylxd/deprecated/tests/test_network.py     |  57 ++++++
 pylxd/deprecated/tests/test_operation.py   |  75 ++++++++
 pylxd/deprecated/tests/test_profiles.py    |  69 ++++++++
 pylxd/deprecated/tests/utils.py            |  42 +++++
 pylxd/tests/__init__.py                    |  40 -----
 pylxd/tests/fake_api.py                    | 272 -----------------------------
 pylxd/tests/test_certificate.py            |  57 ------
 pylxd/tests/test_client.py                 |  90 ----------
 pylxd/tests/test_connection.py             | 172 ------------------
 pylxd/tests/test_container.py              | 222 -----------------------
 pylxd/tests/test_host.py                   |  82 ---------
 pylxd/tests/test_image.py                  | 241 -------------------------
 pylxd/tests/test_image_alias.py            |  66 -------
 pylxd/tests/test_network.py                |  57 ------
 pylxd/tests/test_operation.py              |  75 --------
 pylxd/tests/test_profiles.py               |  69 --------
 pylxd/tests/utils.py                       |  42 -----
 26 files changed, 1485 insertions(+), 1485 deletions(-)
 create mode 100644 pylxd/deprecated/tests/__init__.py
 create mode 100644 pylxd/deprecated/tests/fake_api.py
 create mode 100644 pylxd/deprecated/tests/test_certificate.py
 create mode 100644 pylxd/deprecated/tests/test_client.py
 create mode 100644 pylxd/deprecated/tests/test_connection.py
 create mode 100644 pylxd/deprecated/tests/test_container.py
 create mode 100644 pylxd/deprecated/tests/test_host.py
 create mode 100644 pylxd/deprecated/tests/test_image.py
 create mode 100644 pylxd/deprecated/tests/test_image_alias.py
 create mode 100644 pylxd/deprecated/tests/test_network.py
 create mode 100644 pylxd/deprecated/tests/test_operation.py
 create mode 100644 pylxd/deprecated/tests/test_profiles.py
 create mode 100644 pylxd/deprecated/tests/utils.py
 delete mode 100644 pylxd/tests/__init__.py
 delete mode 100644 pylxd/tests/fake_api.py
 delete mode 100644 pylxd/tests/test_certificate.py
 delete mode 100644 pylxd/tests/test_client.py
 delete mode 100644 pylxd/tests/test_connection.py
 delete mode 100644 pylxd/tests/test_container.py
 delete mode 100644 pylxd/tests/test_host.py
 delete mode 100644 pylxd/tests/test_image.py
 delete mode 100644 pylxd/tests/test_image_alias.py
 delete mode 100644 pylxd/tests/test_network.py
 delete mode 100644 pylxd/tests/test_operation.py
 delete mode 100644 pylxd/tests/test_profiles.py
 delete mode 100644 pylxd/tests/utils.py

diff --git a/pylxd/deprecated/tests/__init__.py b/pylxd/deprecated/tests/__init__.py
new file mode 100644
index 0000000..4780a2b
--- /dev/null
+++ b/pylxd/deprecated/tests/__init__.py
@@ -0,0 +1,40 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import data
+from ddt import unpack
+import unittest
+
+from pylxd import api
+
+
+class LXDAPITestBase(unittest.TestCase):
+
+    def setUp(self):
+        super(LXDAPITestBase, self).setUp()
+        self.lxd = api.API()
+
+
+def annotated_data(*args):
+    class List(list):
+        pass
+
+    new_args = []
+
+    for arg in args:
+        new_arg = List(arg)
+        new_arg.__name__ = arg[0]
+        new_args.append(new_arg)
+
+    return lambda func: data(*new_args)(unpack(func))
diff --git a/pylxd/deprecated/tests/fake_api.py b/pylxd/deprecated/tests/fake_api.py
new file mode 100644
index 0000000..849246e
--- /dev/null
+++ b/pylxd/deprecated/tests/fake_api.py
@@ -0,0 +1,272 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+
+def fake_standard_return():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {}
+    }
+
+
+def fake_host():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+                "api_compat": 1,
+                "auth": "trusted",
+                "config": {},
+                "environment": {
+                    "backing_fs": "ext4",
+                    "driver": "lxc",
+                    "kernel_version": "3.19.0-22-generic",
+                    "lxc_version": "1.1.2",
+                    "lxd_version": "0.12"
+                }
+        }
+    }
+
+
+def fake_image_list_empty():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": []
+    }
+
+
+def fake_image_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": ['/1.0/images/trusty']
+    }
+
+
+def fake_image_info():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+            "aliases": [
+                {
+                    "target": "ubuntu",
+                    "description": "ubuntu"
+                }
+            ],
+            "architecture": 2,
+            "fingerprint": "04aac4257341478b49c25d22cea8a6ce"
+                           "0489dc6c42d835367945e7596368a37f",
+            "filename": "",
+            "properties": {},
+            "public": 0,
+            "size": 67043148,
+            "created_at": 0,
+            "expires_at": 0,
+            "uploaded_at": 1435669853
+        }
+    }
+
+
+def fake_alias():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+                "target": "ubuntu",
+                "description": "ubuntu"
+        }
+    }
+
+
+def fake_alias_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/images/aliases/ubuntu"
+        ]
+    }
+
+
+def fake_container_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/containers/trusty-1"
+        ]
+    }
+
+
+def fake_container_state(status):
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+            "status": status
+        }
+    }
+
+
+def fake_container_log():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+            "log": "fake log"
+        }
+    }
+
+
+def fake_container_migrate():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "operation": "/1.0/operations/1234",
+        "metadata": {
+            "control": "fake_control",
+            "fs": "fake_fs",
+            "criu": "fake_criu",
+        }
+    }
+
+
+def fake_snapshots_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/containers/trusty-1/snapshots/first"
+        ]
+    }
+
+
+def fake_certificate_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/certificates/ABCDEF01"
+        ]
+    }
+
+
+def fake_certificate():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+            "type": "client",
+            "certificate": "ABCDEF01"
+        }
+    }
+
+
+def fake_profile_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/profiles/fake-profile"
+        ]
+    }
+
+
+def fake_profile():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": {
+            "name": "fake-profile",
+            "config": {
+                "resources.memory": "2GB",
+                "network.0.bridge": "lxcbr0"
+            }
+        }
+    }
+
+
+def fake_operation_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/operations/1234"
+        ]
+    }
+
+
+def fake_operation():
+    return {
+        "type": "async",
+        "status": "OK",
+        "status_code": 100,
+        "operation": "/1.0/operation/1234",
+        "metadata": {
+            "created_at": "2015-06-09T19:07:24.379615253-06:00",
+            "updated_at": "2015-06-09T19:07:23.379615253-06:00",
+            "status": "Running",
+            "status_code": 103,
+            "resources": {
+                "containers": ["/1.0/containers/1"]
+            },
+            "metadata": {},
+            "may_cancel": True
+        }
+    }
+
+
+def fake_network_list():
+    return {
+        "type": "sync",
+        "status": "Success",
+        "status_code": 200,
+        "metadata": [
+            "/1.0/networks/lxcbr0"
+        ]
+    }
+
+
+def fake_network():
+    return {
+        "type": "async",
+        "status": "OK",
+        "status_code": 100,
+        "operation": "/1.0/operation/1234",
+        "metadata": {
+            "name": "lxcbr0",
+            "type": "bridge",
+            "members": ["/1.0/containers/trusty-1"]
+        }
+    }
diff --git a/pylxd/deprecated/tests/test_certificate.py b/pylxd/deprecated/tests/test_certificate.py
new file mode 100644
index 0000000..1dab145
--- /dev/null
+++ b/pylxd/deprecated/tests/test_certificate.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import ddt
+import json
+import mock
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+class LXDAPICertificateTest(LXDAPITestBase):
+
+    def test_list_certificates(self):
+        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
+            ms.return_value = ('200', fake_api.fake_certificate_list())
+            self.assertEqual(
+                ['ABCDEF01'],
+                self.lxd.certificate_list())
+            ms.assert_called_with('GET',
+                                  '/1.0/certificates')
+
+    def test_certificate_show(self):
+        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
+            ms.return_value = ('200', fake_api.fake_certificate())
+            self.assertEqual(
+                ms.return_value, self.lxd.certificate_show('ABCDEF01'))
+            ms.assert_called_with('GET',
+                                  '/1.0/certificates/ABCDEF01')
+
+    @annotated_data(
+        ('delete', 'DELETE', '/ABCDEF01'),
+        ('create', 'POST', '', (json.dumps('ABCDEF01'),)),
+    )
+    def test_certificate_operations(self, method, http, path, call_args=()):
+        with mock.patch.object(connection.LXDConnection, 'get_status') as ms:
+            ms.return_value = True
+            self.assertTrue(
+                getattr(self.lxd, 'certificate_' + method)('ABCDEF01'))
+            ms.assert_called_with(http,
+                                  '/1.0/certificates' + path,
+                                  *call_args)
diff --git a/pylxd/deprecated/tests/test_client.py b/pylxd/deprecated/tests/test_client.py
new file mode 100644
index 0000000..821c59d
--- /dev/null
+++ b/pylxd/deprecated/tests/test_client.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2016 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""Tests for pylxd.client."""
+import unittest
+
+import mock
+
+from pylxd import client
+
+
+class Test_APINode(unittest.TestCase):
+    """Tests for pylxd.client._APINode."""
+    ROOT = 'http://lxd/api'
+
+    def test_getattr(self):
+        """`__getattr__` returns a nested node."""
+        lxd = client._APINode(self.ROOT)
+
+        self.assertEqual('{}/fake'.format(self.ROOT), lxd.fake._api_endpoint)
+
+    def test_getattr_nested(self):
+        """Nested objects return a more detailed path."""
+        lxd = client._APINode(self.ROOT)  # NOQA
+
+        self.assertEqual(
+            '{}/fake/path'.format(self.ROOT),
+            lxd.fake.path._api_endpoint)
+
+    def test_getitem(self):
+        """`__getitem__` enables dynamic url parts."""
+        lxd = client._APINode(self.ROOT)  # NOQA
+
+        self.assertEqual(
+            '{}/fake/path'.format(self.ROOT),
+            lxd.fake['path']._api_endpoint)
+
+    def test_getitem_integer(self):
+        """`__getitem__` with an integer allows dynamic integer url parts."""
+        lxd = client._APINode(self.ROOT)  # NOQA
+
+        self.assertEqual(
+            '{}/fake/0'.format(self.ROOT),
+            lxd.fake[0]._api_endpoint)
+
+    @mock.patch('pylxd.client.requests.get')
+    def test_get(self, _get):
+        """`get` will make a request to the smart url."""
+        lxd = client._APINode(self.ROOT)
+
+        lxd.fake.get()
+
+        _get.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
+
+    @mock.patch('pylxd.client.requests.post')
+    def test_post(self, _post):
+        """`post` will POST to the smart url."""
+        lxd = client._APINode(self.ROOT)
+
+        lxd.fake.post()
+
+        _post.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
+
+    @mock.patch('pylxd.client.requests.put')
+    def test_put(self, _put):
+        """`put` will PUT to the smart url."""
+        lxd = client._APINode(self.ROOT)
+
+        lxd.fake.put()
+
+        _put.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
+
+    @mock.patch('pylxd.client.requests.delete')
+    def test_delete(self, _delete):
+        """`delete` will DELETE to the smart url."""
+        lxd = client._APINode(self.ROOT)
+
+        lxd.fake.delete()
+
+        _delete.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
diff --git a/pylxd/deprecated/tests/test_connection.py b/pylxd/deprecated/tests/test_connection.py
new file mode 100644
index 0000000..33c4ce9
--- /dev/null
+++ b/pylxd/deprecated/tests/test_connection.py
@@ -0,0 +1,172 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import ddt
+import inspect
+import mock
+import six
+from six.moves import cStringIO
+from six.moves import http_client
+import socket
+import unittest
+
+from pylxd.deprecated import connection
+from pylxd.deprecated import exceptions
+from pylxd.deprecated.tests import annotated_data
+
+if six.PY34:
+    from io import BytesIO
+
+
+ at ddt
+class LXDInitConnectionTest(unittest.TestCase):
+
+    @mock.patch('socket.socket')
+    @mock.patch.object(http_client.HTTPConnection, '__init__')
+    def test_http_connection(self, mc, ms):
+        conn = connection.UnixHTTPConnection('/', 'host', 1234)
+        if six.PY34:
+            mc.assert_called_once_with(
+                conn, 'host', port=1234, timeout=None)
+        else:
+            mc.assert_called_once_with(
+                conn, 'host', port=1234, strict=None, timeout=None)
+        conn.connect()
+        ms.assert_called_once_with(socket.AF_UNIX, socket.SOCK_STREAM)
+        ms.return_value.connect.assert_called_once_with('/')
+
+    @mock.patch('os.environ', {'HOME': '/home/foo'})
+    @mock.patch('ssl.wrap_socket')
+    @mock.patch('socket.create_connection')
+    def test_https_connection(self, ms, ml):
+        conn = connection.HTTPSConnection('host', 1234)
+        with mock.patch.object(conn, '_tunnel') as mc:
+            conn.connect()
+            self.assertFalse(mc.called)
+            ms.assert_called_once_with(
+                ('host', 1234), socket._GLOBAL_DEFAULT_TIMEOUT, None)
+            ml.assert_called_once_with(
+                ms.return_value,
+                certfile='/home/foo/.config/lxc/client.crt',
+                keyfile='/home/foo/.config/lxc/client.key',
+                ssl_version=connection.DEFAULT_TLS_VERSION,
+            )
+
+    @mock.patch('os.environ', {'HOME': '/home/foo'})
+    @mock.patch('ssl.wrap_socket')
+    @mock.patch('socket.create_connection')
+    def test_https_proxy_connection(self, ms, ml):
+        conn = connection.HTTPSConnection('host', 1234)
+        conn._tunnel_host = 'host'
+        with mock.patch.object(conn, '_tunnel') as mc:
+            conn.connect()
+            self.assertTrue(mc.called)
+            ms.assert_called_once_with(
+                ('host', 1234), socket._GLOBAL_DEFAULT_TIMEOUT, None)
+            ml.assert_called_once_with(
+                ms.return_value,
+                certfile='/home/foo/.config/lxc/client.crt',
+                keyfile='/home/foo/.config/lxc/client.key',
+                ssl_version=connection.DEFAULT_TLS_VERSION)
+
+    @mock.patch('pylxd.deprecated.connection.HTTPSConnection')
+    @mock.patch('pylxd.deprecated.connection.UnixHTTPConnection')
+    @annotated_data(
+        ('unix', (None,), {}, '/var/lib/lxd/unix.socket'),
+        ('unix_path', (None,),
+         {'LXD_DIR': '/fake/'}, '/fake/unix.socket'),
+        ('https', ('host',), {}, ''),
+        ('https_port', ('host', 1234), {}, ''),
+    )
+    def test_get_connection(self, mode, args, env, path, mc, ms):
+        with mock.patch('os.environ', env):
+            conn = connection.LXDConnection(*args).get_connection()
+            if mode.startswith('unix'):
+                self.assertEqual(mc.return_value, conn)
+                mc.assert_called_once_with(path)
+            elif mode.startswith('https'):
+                self.assertEqual(ms.return_value, conn)
+                ms.assert_called_once_with(
+                    args[0], len(args) == 2 and args[1] or 8443)
+
+
+class FakeResponse(object):
+
+    def __init__(self, status, data):
+        self.status = status
+        if six.PY34:
+            self.read = BytesIO(six.b(data)).read
+        else:
+            self.read = cStringIO(data).read
+
+
+ at ddt
+ at mock.patch('pylxd.deprecated.connection.LXDConnection.get_connection')
+class LXDConnectionTest(unittest.TestCase):
+
+    def setUp(self):
+        super(LXDConnectionTest, self).setUp()
+        self.conn = connection.LXDConnection()
+
+    @annotated_data(
+        ('null', (200, '{}'), exceptions.PyLXDException),
+        ('200', (200, '{"foo": "bar"}'), (200, {'foo': 'bar'})),
+        ('202', (202, '{"status_code": 100}'), (202, {'status_code': 100})),
+        ('500', (500, '{"foo": "bar"}'), exceptions.APIError),
+    )
+    def test_get_object(self, tag, effect, result, mg):
+        mg.return_value.getresponse.return_value = FakeResponse(*effect)
+        if inspect.isclass(result):
+            self.assertRaises(result, self.conn.get_object)
+        else:
+            self.assertEqual(result, self.conn.get_object())
+
+    @annotated_data(
+        ('null', (200, '{}'), exceptions.PyLXDException),
+        ('200', (200, '{"foo": "bar"}'), True),
+        ('202', (202, '{"status_code": 100}'), True),
+        ('200', (200, '{"error": "bar"}'), exceptions.APIError),
+        ('500', (500, '{"foo": "bar"}'), False),
+    )
+    def test_get_status(self, tag, effect, result, mg):
+        mg.return_value.getresponse.return_value = FakeResponse(*effect)
+        if inspect.isclass(result):
+            self.assertRaises(result, self.conn.get_status)
+        else:
+            self.assertEqual(result, self.conn.get_status())
+
+    @annotated_data(
+        ('null', (200, ''), exceptions.PyLXDException),
+        ('200', (200, '{"foo": "bar"}'), six.b('{"foo": "bar"}')),
+        ('500', (500, '{"foo": "bar"}'),
+         exceptions.PyLXDException),
+    )
+    def test_get_raw(self, tag, effect, result, mg):
+        mg.return_value.getresponse.return_value = FakeResponse(*effect)
+        if inspect.isclass(result):
+            self.assertRaises(result, self.conn.get_raw)
+        else:
+            self.assertEqual(result, self.conn.get_raw())
+
+    @mock.patch('pylxd.deprecated.connection.WebSocketClient')
+    @annotated_data(
+        ('fake_host', 'wss://fake_host:8443'),
+        (None, 'ws+unix:///var/lib/lxd/unix.socket')
+    )
+    def test_get_ws(self, host, result, mock_ws, _):
+        conn = connection.LXDConnection(host)
+
+        conn.get_ws('/fake/path')
+
+        mock_ws.assert_has_calls([mock.call(result), mock.call().connect()])
diff --git a/pylxd/deprecated/tests/test_container.py b/pylxd/deprecated/tests/test_container.py
new file mode 100644
index 0000000..5c57f36
--- /dev/null
+++ b/pylxd/deprecated/tests/test_container.py
@@ -0,0 +1,222 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from collections import OrderedDict
+from ddt import ddt
+import json
+import mock
+import tempfile
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=('200', fake_api.fake_operation()))
+class LXDAPIContainerTestObject(LXDAPITestBase):
+
+    def test_list_containers(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_list())
+        self.assertEqual(
+            ['trusty-1'],
+            self.lxd.container_list())
+        ms.assert_called_once_with('GET',
+                                   '/1.0/containers')
+
+    @annotated_data(
+        ('STOPPED', False),
+        ('STOPPING', False),
+        ('ABORTING', False),
+        ('RUNNING', True),
+        ('STARTING', True),
+        ('FREEZING', True),
+        ('FROZEN', True),
+        ('THAWED', True),
+    )
+    def test_container_running(self, status, running, ms):
+        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
+            ms.return_value = ('200', fake_api.fake_container_state(status))
+            self.assertEqual(running, self.lxd.container_running('trusty-1'))
+            ms.assert_called_once_with('GET',
+                                       '/1.0/containers/trusty-1/state')
+
+    def test_container_init(self, ms):
+        self.assertEqual(ms.return_value, self.lxd.container_init('fake'))
+        ms.assert_called_once_with('POST',
+                                   '/1.0/containers',
+                                   '"fake"')
+
+    def test_container_update(self, ms):
+        self.assertEqual(ms.return_value,
+                         self.lxd.container_update('trusty-1',
+                                                   'fake'))
+        ms.assert_called_once_with('PUT',
+                                   '/1.0/containers/trusty-1',
+                                   '"fake"')
+
+    def test_container_state(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_state('RUNNING'))
+        self.assertEqual(ms.return_value, self.lxd.container_state('trusty-1'))
+        ms.assert_called_with('GET',
+                              '/1.0/containers/trusty-1/state')
+
+    @annotated_data(
+        ('start', 'start'),
+        ('stop', 'stop'),
+        ('suspend', 'freeze'),
+        ('resume', 'unfreeze'),
+        ('reboot', 'restart'),
+    )
+    def test_container_actions(self, method, action, ms):
+        self.assertEqual(
+            ms.return_value,
+            getattr(self.lxd, 'container_' + method)('trusty-1', 30))
+        ms.assert_called_once_with('PUT',
+                                   '/1.0/containers/trusty-1/state',
+                                   json.dumps({'action': action,
+                                               'force': True,
+                                               'timeout': 30, }))
+
+    def test_container_destroy(self, ms):
+        self.assertEqual(
+            ms.return_value, self.lxd.container_destroy('trusty-1'))
+        ms.assert_called_once_with('DELETE',
+                                   '/1.0/containers/trusty-1')
+
+    def test_container_log(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_log())
+        self.assertEqual(
+            'fake log', self.lxd.get_container_log('trusty-1'))
+        ms.assert_called_once_with('GET',
+                                   '/1.0/containers/trusty-1?log=true')
+
+    def test_container_config(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_state('fake'))
+        self.assertEqual(
+            {'status': 'fake'}, self.lxd.get_container_config('trusty-1'))
+        ms.assert_called_once_with('GET',
+                                   '/1.0/containers/trusty-1?log=false')
+
+    def test_container_info(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_state('fake'))
+        self.assertEqual(
+            {'status': 'fake'}, self.lxd.container_info('trusty-1'))
+        ms.assert_called_once_with('GET',
+                                   '/1.0/containers/trusty-1/state')
+
+    def test_container_migrate(self, ms):
+        ms.return_value = ('200', fake_api.fake_container_migrate())
+        self.assertEqual(
+            {'control': 'fake_control',
+             'criu': 'fake_criu',
+             'fs': 'fake_fs',
+             'operation': '1234'},
+            self.lxd.container_migrate('trusty-1'))
+        ms.assert_called_once_with('POST',
+                                   '/1.0/containers/trusty-1',
+                                   '{"migration": true}')
+
+    def test_container_publish(self, ms):
+        ms.return_value = ('200', fake_api.fake_operation())
+        self.assertEqual(
+            ms.return_value, self.lxd.container_publish('trusty-1'))
+        ms.assert_called_once_with('POST',
+                                   '/1.0/images',
+                                   '"trusty-1"')
+
+    def test_container_put_file(self, ms):
+        temp_file = tempfile.NamedTemporaryFile()
+        ms.return_value = ('200', fake_api.fake_standard_return())
+        self.assertEqual(
+            ms.return_value, self.lxd.put_container_file('trusty-1',
+                                                         temp_file.name,
+                                                         'dst_file'))
+        ms.assert_called_once_with(
+            'POST',
+            '/1.0/containers/trusty-1/files?path=dst_file',
+            body=b'',
+            headers={'X-LXD-gid': 0, 'X-LXD-mode': 0o644, 'X-LXD-uid': 0})
+
+    def test_list_snapshots(self, ms):
+        ms.return_value = ('200', fake_api.fake_snapshots_list())
+        self.assertEqual(
+            ['/1.0/containers/trusty-1/snapshots/first'],
+            self.lxd.container_snapshot_list('trusty-1'))
+        ms.assert_called_once_with('GET',
+                                   '/1.0/containers/trusty-1/snapshots')
+
+    @annotated_data(
+        ('create', 'POST', '', ('fake config',), ('"fake config"',)),
+        ('info', 'GET', '/first', ('first',), ()),
+        ('rename', 'POST', '/first',
+         ('first', 'fake config'), ('"fake config"',)),
+        ('delete', 'DELETE', '/first', ('first',), ()),
+    )
+    def test_snapshot_operations(self, method, http, path,
+                                 args, call_args, ms):
+        self.assertEqual(
+            ms.return_value,
+            getattr(self.lxd,
+                    'container_snapshot_' + method)('trusty-1', *args))
+        ms.assert_called_once_with(http,
+                                   '/1.0/containers/trusty-1/snapshots' +
+                                   path,
+                                   *call_args)
+
+    def test_container_run_command(self, ms):
+        data = OrderedDict((
+            ('command', ['/fake/command']),
+            ('interactive', False),
+            ('wait-for-websocket', False),
+            ('environment', {'FAKE_ENV': 'fake'})
+        ))
+
+        self.assertEqual(
+            ms.return_value,
+            self.lxd.container_run_command('trusty-1', *data.values()))
+        self.assertEqual(1, ms.call_count)
+        self.assertEqual(
+            ms.call_args[0][:2],
+            ('POST', '/1.0/containers/trusty-1/exec'))
+        self.assertEqual(
+            json.loads(ms.call_args[0][2]),
+            dict(data)
+        )
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=('200', fake_api.fake_container_list()))
+class LXDAPIContainerTestStatus(LXDAPITestBase):
+
+    def test_container_defined(self, ms):
+        self.assertTrue(self.lxd.container_defined('trusty-1'))
+        ms.assert_called_once_with('GET', '/1.0/containers')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_raw',
+                   return_value='fake contents')
+class LXDAPIContainerTestRaw(LXDAPITestBase):
+
+    def test_container_file(self, ms):
+        self.assertEqual(
+            'fake contents', self.lxd.get_container_file('trusty-1',
+                                                         '/file/name'))
+        ms.assert_called_once_with(
+            'GET', '/1.0/containers/trusty-1/files?path=/file/name')
diff --git a/pylxd/deprecated/tests/test_host.py b/pylxd/deprecated/tests/test_host.py
new file mode 100644
index 0000000..4fc8fd1
--- /dev/null
+++ b/pylxd/deprecated/tests/test_host.py
@@ -0,0 +1,82 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import data
+from ddt import ddt
+import mock
+
+from pylxd.deprecated import connection
+from pylxd.deprecated import exceptions
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=('200', fake_api.fake_host()))
+class LXDAPIHostTestObject(LXDAPITestBase):
+
+    def test_get_host_info(self, ms):
+        result = self.lxd.host_info()
+        self.assertEqual(result, {
+            'lxd_api_compat_level': 1,
+            'lxd_trusted_host': True,
+            'lxd_backing_fs': 'ext4',
+            'lxd_driver': 'lxc',
+            'lxd_version': 0.12,
+            'lxc_version': '1.1.2',
+            'kernel_version': '3.19.0-22-generic',
+        })
+        ms.assert_called_once_with('GET', '/1.0')
+
+    host_data = (
+        ('lxd_api_compat', 1),
+        ('lxd_host_trust', True),
+        ('lxd_backing_fs', 'ext4'),
+        ('lxd_driver', 'lxc'),
+        ('lxc_version', '1.1.2'),
+        ('lxd_version', 0.12),
+        ('kernel_version', '3.19.0-22-generic'),
+    )
+
+    @annotated_data(*host_data)
+    def test_get_host_data(self, method, expected, ms):
+        result = getattr(self.lxd, 'get_' + method)(data=None)
+        self.assertEqual(expected, result)
+        ms.assert_called_once_with('GET', '/1.0')
+
+    @annotated_data(*host_data)
+    def test_get_host_data_fail(self, method, expected, ms):
+        ms.side_effect = exceptions.PyLXDException
+        result = getattr(self.lxd, 'get_' + method)(data=None)
+        self.assertEqual(None, result)
+        ms.assert_called_once_with('GET', '/1.0')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_status')
+class LXDAPIHostTestStatus(LXDAPITestBase):
+
+    @data(True, False)
+    def test_get_host_ping(self, value, ms):
+        ms.return_value = value
+        self.assertEqual(value, self.lxd.host_ping())
+        ms.assert_called_once_with('GET', '/1.0')
+
+    def test_get_host_ping_fail(self, ms):
+        ms.side_effect = Exception
+        self.assertRaises(exceptions.PyLXDException, self.lxd.host_ping)
+        ms.assert_called_once_with('GET', '/1.0')
diff --git a/pylxd/deprecated/tests/test_image.py b/pylxd/deprecated/tests/test_image.py
new file mode 100644
index 0000000..56bdc84
--- /dev/null
+++ b/pylxd/deprecated/tests/test_image.py
@@ -0,0 +1,241 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import datetime
+from ddt import ddt
+import mock
+from six.moves import builtins
+from six.moves import cStringIO
+import unittest
+
+from pylxd.deprecated import connection
+from pylxd.deprecated import exceptions
+from pylxd.deprecated import image
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=('200', fake_api.fake_image_info()))
+class LXDAPIImageTestObject(LXDAPITestBase):
+
+    list_data = (
+        ('list', (), ()),
+        ('search', ({'foo': 'bar'},), ('foo=bar',)),
+    )
+
+    @annotated_data(*list_data)
+    def test_list_images(self, method, args, call_args, ms):
+        ms.return_value = ('200', fake_api.fake_image_list())
+        self.assertEqual(
+            ['trusty'], getattr(self.lxd, 'image_' + method)(*args))
+        ms.assert_called_once_with('GET', '/1.0/images', *call_args)
+
+    @annotated_data(*list_data)
+    def test_list_images_fail(self, method, args, call_args, ms):
+        ms.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException,
+                          getattr(self.lxd, 'image_' + method),
+                          *args)
+        ms.assert_called_once_with('GET', '/1.0/images', *call_args)
+
+    @annotated_data(
+        (True, (('200', fake_api.fake_image_info()),)),
+        (False, exceptions.APIError("404", 404)),
+    )
+    def test_image_defined(self, expected, side_effect, ms):
+        ms.side_effect = side_effect
+        self.assertEqual(expected, self.lxd.image_defined('test-image'))
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    @annotated_data(
+        ('APIError', exceptions.APIError("500", 500), exceptions.APIError),
+        ('PyLXDException', exceptions.PyLXDException,
+         exceptions.PyLXDException)
+    )
+    def test_image_defined_fail(self, tag, side_effect, expected, ms):
+        ms.side_effect = side_effect
+        self.assertRaises(expected,
+                          self.lxd.image_defined, ('test-image',))
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    def test_image_info(self, ms):
+        self.assertEqual({
+            'image_upload_date': (datetime.datetime
+                                  .fromtimestamp(1435669853)
+                                  .strftime('%Y-%m-%d %H:%M:%S')),
+            'image_created_date': 'Unknown',
+            'image_expires_date': 'Unknown',
+            'image_public': False,
+            'image_size': '63MB',
+            'image_fingerprint': '04aac4257341478b49c25d22cea8a6ce'
+                                 '0489dc6c42d835367945e7596368a37f',
+            'image_architecture': 'x86_64',
+        }, self.lxd.image_info('test-image'))
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    def test_image_info_fail(self, ms):
+        ms.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException,
+                          self.lxd.image_info, ('test-image',))
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    dates_data = (
+        ('upload', (datetime.datetime.fromtimestamp(1435669853)
+                    .strftime('%Y-%m-%d %H:%M:%S'))),
+        ('create', 'Unknown'),
+        ('expire', 'Unknown'),
+    )
+
+    @annotated_data(*dates_data)
+    def test_image_date(self, method, expected, ms):
+        self.assertEqual(expected, getattr(
+            self.lxd, 'image_{}_date'.format(method))('test-image',
+                                                      data=None))
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    @annotated_data(*dates_data)
+    def test_image_date_fail(self, method, expected, ms):
+        ms.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException, getattr(
+            self.lxd,
+            'image_{}_date'.format(method)),
+            'test-image',
+            data=None)
+        ms.assert_called_once_with('GET', '/1.0/images/test-image')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
+class LXDAPIImageTestStatus(LXDAPITestBase):
+    operations_data = (
+        ('delete', 'DELETE', '/test-image', ('test-image',), ()),
+        ('update', 'PUT', '/test-image', ('test-image', 'fake',), ('"fake"',)),
+        ('rename', 'POST', '/test-image',
+         ('test-image', 'fake',), ('"fake"',)),
+    )
+
+    @annotated_data(*operations_data)
+    def test_image_operations(self, method, http, path, args, call_args, ms):
+        self.assertTrue(
+            getattr(self.lxd, 'image_' + method)(*args))
+        ms.assert_called_once_with(
+            http,
+            '/1.0/images' + path,
+            *call_args
+        )
+
+    @annotated_data(*operations_data)
+    def test_image_operations_fail(self, method, http, path,
+                                   args, call_args, ms):
+        ms.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException,
+                          getattr(self.lxd, 'image_' + method),
+                          *args)
+        ms.assert_called_once_with(
+            http,
+            '/1.0/images' + path,
+            *call_args
+        )
+
+
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=('200', fake_api.fake_image_info()))
+class LXDAPAPIImageTestUpload(LXDAPITestBase):
+    @mock.patch.object(builtins, 'open', return_value=cStringIO('fake'))
+    def test_image_upload_file(self, mo, ms):
+        self.assertTrue(self.lxd.image_upload(path='/fake/path'))
+        mo.assert_called_once_with('/fake/path', 'rb')
+        ms.assert_called_once_with('POST', '/1.0/images', 'fake', {})
+
+
+ at mock.patch.object(connection.LXDConnection, 'get_raw')
+class LXDAPIImageTestRaw(LXDAPITestBase):
+
+    def test_image_export(self, ms):
+        ms.return_value = 'fake contents'
+        self.assertEqual('fake contents', self.lxd.image_export('fake'))
+        ms.assert_called_once_with('GET', '/1.0/images/fake/export')
+
+    def test_image_export_fail(self, ms):
+        ms.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException,
+                          self.lxd.image_export, 'fake')
+        ms.assert_called_once_with('GET', '/1.0/images/fake/export')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=(200, fake_api.fake_image_info()))
+class LXDAPIImageInfoTest(unittest.TestCase):
+
+    def setUp(self):
+        super(LXDAPIImageInfoTest, self).setUp()
+        self.image = image.LXDImage()
+
+    info_list = (
+        ('permission', False),
+        ('size', 63),
+        ('fingerprint', '04aac4257341478b49c25d22cea8a6ce'
+                        '0489dc6c42d835367945e7596368a37f'),
+        ('architecture', 'x86_64'),
+    )
+
+    @annotated_data(*info_list)
+    def test_info_no_data(self, method, expected, mc):
+        self.assertEqual(expected,
+                         (getattr(self.image, 'get_image_' + method)
+                          ('test-image', data=None)))
+        mc.assert_called_once_with('GET', '/1.0/images/test-image')
+
+    @annotated_data(*info_list)
+    def test_info_no_data_fail(self, method, expected, mc):
+        mc.side_effect = exceptions.PyLXDException
+        self.assertRaises(exceptions.PyLXDException,
+                          getattr(self.image, 'get_image_' + method),
+                          'test-image',
+                          data=None)
+
+    @annotated_data(
+        ('permission_true', 'permission', {'public': 0}, False),
+        ('permission_false', 'permission', {'public': 1}, True),
+        ('size', 'size', {'size': 52428800}, 50),
+        ('fingerprint', 'fingerprint', {'fingerprint': 'AAAA'}, 'AAAA'),
+        *[('architecture_' + v, 'architecture', {'architecture': k}, v)
+          for k, v in image.image_architecture.items()]
+    )
+    def test_info_data(self, tag, method, metadata, expected, mc):
+        self.assertEqual(
+            expected, getattr(self.image, 'get_image_' + method)
+            ('test-image', data=metadata))
+        self.assertFalse(mc.called)
+
+    @annotated_data(
+        ('permission', 'permission', {}, KeyError),
+        ('size', 'size', {'size': 0}, exceptions.ImageInvalidSize),
+        ('size', 'size', {'size': -1}, exceptions.ImageInvalidSize),
+        ('fingerprint', 'fingerprint', {}, KeyError),
+        ('architecture', 'architecture', {}, KeyError),
+        ('architecture_invalid', 'architecture',
+         {'architecture': -1}, KeyError)
+    )
+    def test_info_data_fail(self, tag, method, metadata, expected, mc):
+        self.assertRaises(expected,
+                          getattr(self.image, 'get_image_' + method),
+                          'test-image',
+                          data=metadata)
+        self.assertFalse(mc.called)
diff --git a/pylxd/deprecated/tests/test_image_alias.py b/pylxd/deprecated/tests/test_image_alias.py
new file mode 100644
index 0000000..74caec6
--- /dev/null
+++ b/pylxd/deprecated/tests/test_image_alias.py
@@ -0,0 +1,66 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import data
+from ddt import ddt
+import mock
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object')
+class LXDAPIImageAliasTestObject(LXDAPITestBase):
+
+    def test_alias_list(self, ms):
+        ms.return_value = ('200', fake_api.fake_alias_list())
+        self.assertEqual(['ubuntu'], self.lxd.alias_list())
+        ms.assert_called_once_with('GET', '/1.0/images/aliases')
+
+    def test_alias_show(self, ms):
+        ms.return_value = ('200', fake_api.fake_alias())
+        self.assertEqual(
+            fake_api.fake_alias(), self.lxd.alias_show('fake')[1])
+        ms.assert_called_once_with('GET', '/1.0/images/aliases/fake')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_status')
+class LXDAPIImageAliasTestStatus(LXDAPITestBase):
+
+    @data(True, False)
+    def test_alias_defined(self, expected, ms):
+        ms.return_value = expected
+        self.assertEqual(expected, self.lxd.alias_defined('fake'))
+        ms.assert_called_once_with('GET', '/1.0/images/aliases/fake')
+
+    @annotated_data(
+        ('create', 'POST', '', ('fake',), ('"fake"',)),
+        ('update', 'PUT', '/test-alias',
+         ('test-alias', 'fake',), ('"fake"',)),
+        ('rename', 'POST', '/test-alias',
+         ('test-alias', 'fake',), ('"fake"',)),
+        ('delete', 'DELETE', '/test-alias', ('test-alias',), ()),
+    )
+    def test_alias_operations(self, method, http, path, args, call_args, ms):
+        self.assertTrue(getattr(self.lxd, 'alias_' + method)(*args))
+        ms.assert_called_once_with(
+            http,
+            '/1.0/images/aliases' + path,
+            *call_args
+        )
diff --git a/pylxd/deprecated/tests/test_network.py b/pylxd/deprecated/tests/test_network.py
new file mode 100644
index 0000000..e455923
--- /dev/null
+++ b/pylxd/deprecated/tests/test_network.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import ddt
+import mock
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=(200, fake_api.fake_network()))
+class LXDAPINetworkTest(LXDAPITestBase):
+
+    def test_list_networks(self, ms):
+        ms.return_value = ('200', fake_api.fake_network_list())
+        self.assertEqual(
+            ['lxcbr0'],
+            self.lxd.network_list())
+        ms.assert_called_with('GET',
+                              '/1.0/networks')
+
+    def test_network_show(self, ms):
+        self.assertEqual({
+            'network_name': 'lxcbr0',
+            'network_type': 'bridge',
+            'network_members': ['/1.0/containers/trusty-1'],
+        }, self.lxd.network_show('lxcbr0'))
+        ms.assert_called_with('GET',
+                              '/1.0/networks/lxcbr0')
+
+    @annotated_data(
+        ('name', 'lxcbr0'),
+        ('type', 'bridge'),
+        ('members', ['/1.0/containers/trusty-1']),
+    )
+    def test_network_data(self, method, expected, ms):
+        self.assertEqual(
+            expected, getattr(self.lxd,
+                              'network_show_' + method)('lxcbr0'))
+        ms.assert_called_with('GET',
+                              '/1.0/networks/lxcbr0')
diff --git a/pylxd/deprecated/tests/test_operation.py b/pylxd/deprecated/tests/test_operation.py
new file mode 100644
index 0000000..fb275e5
--- /dev/null
+++ b/pylxd/deprecated/tests/test_operation.py
@@ -0,0 +1,75 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import datetime
+from ddt import ddt
+import mock
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=(200, fake_api.fake_operation()))
+class LXDAPIOperationTestObject(LXDAPITestBase):
+
+    def test_list_operations(self, ms):
+        ms.return_value = ('200', fake_api.fake_operation_list())
+        self.assertEqual(
+            ['/1.0/operations/1234'],
+            self.lxd.list_operations())
+        ms.assert_called_with('GET',
+                              '/1.0/operations')
+
+    def test_operation_info(self, ms):
+        ms.return_value = ('200', fake_api.fake_operation())
+        self.assertEqual(
+            ms.return_value, self.lxd.operation_info('/1.0/operations/1234'))
+        ms.assert_called_with('GET',
+                              '/1.0/operations/1234')
+
+    @annotated_data(
+        ('create_time',
+         datetime.datetime.utcfromtimestamp(1433876844)
+         .strftime('%Y-%m-%d %H:%M:%S')),
+        ('update_time',
+         datetime.datetime.utcfromtimestamp(1433876843)
+         .strftime('%Y-%m-%d %H:%M:%S')),
+        ('status', 'Running'),
+    )
+    def test_operation_show(self, method, expected, ms):
+        call = getattr(self.lxd, 'operation_show_' + method)
+        self.assertEqual(expected, call('/1.0/operations/1234'))
+        ms.assert_called_with('GET',
+                              '/1.0/operations/1234')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
+class LXDAPIOperationTestStatus(LXDAPITestBase):
+
+    @annotated_data(
+        ('operation_delete', 'DELETE', '', ()),
+        ('wait_container_operation', 'GET',
+         '/wait?status_code=200&timeout=30', ('200', '30')),
+    )
+    def test_operation_actions(self, method, http, path, args, ms):
+        self.assertTrue(
+            getattr(self.lxd, method)('/1.0/operations/1234', *args))
+        ms.assert_called_with(http,
+                              '/1.0/operations/1234' + path)
diff --git a/pylxd/deprecated/tests/test_profiles.py b/pylxd/deprecated/tests/test_profiles.py
new file mode 100644
index 0000000..6e5e8c8
--- /dev/null
+++ b/pylxd/deprecated/tests/test_profiles.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ddt import data
+from ddt import ddt
+import mock
+
+from pylxd.deprecated import connection
+
+from pylxd.deprecated.tests import annotated_data
+from pylxd.deprecated.tests import fake_api
+from pylxd.deprecated.tests import LXDAPITestBase
+
+
+ at mock.patch.object(connection.LXDConnection, 'get_object',
+                   return_value=(200, fake_api.fake_profile()))
+class LXDAPIProfilesTestObject(LXDAPITestBase):
+
+    def test_list_profiles(self, ms):
+        ms.return_value = ('200', fake_api.fake_profile_list())
+        self.assertEqual(
+            ['fake-profile'],
+            self.lxd.profile_list())
+        ms.assert_called_with('GET',
+                              '/1.0/profiles')
+
+    def test_profile_show(self, ms):
+        self.assertEqual(
+            ms.return_value, self.lxd.profile_show('fake-profile'))
+        ms.assert_called_with('GET',
+                              '/1.0/profiles/fake-profile')
+
+
+ at ddt
+ at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
+class LXDAPIProfilesTestStatus(LXDAPITestBase):
+
+    @data(True, False)
+    def test_profile_defined(self, defined, ms):
+        ms.return_value = defined
+        self.assertEqual(defined, self.lxd.profile_defined('fake-profile'))
+        ms.assert_called_with('GET',
+                              '/1.0/profiles/fake-profile')
+
+    @annotated_data(
+        ('create', 'POST', '', ('fake config',), ('"fake config"',)),
+        ('update', 'PUT', '/fake-profile',
+         ('fake-profile', 'fake config',), ('"fake config"',)),
+        ('rename', 'POST', '/fake-profile',
+         ('fake-profile', 'fake config',), ('"fake config"',)),
+        ('delete', 'DELETE', '/fake-profile', ('fake-profile',), ()),
+    )
+    def test_profile_operations(self, method, http, path, args, call_args, ms):
+        self.assertTrue(
+            getattr(self.lxd, 'profile_' + method)(*args))
+        ms.assert_called_with(http,
+                              '/1.0/profiles' + path,
+                              *call_args)
diff --git a/pylxd/deprecated/tests/utils.py b/pylxd/deprecated/tests/utils.py
new file mode 100644
index 0000000..ec424bf
--- /dev/null
+++ b/pylxd/deprecated/tests/utils.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2015 Canonical Ltd
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from pylxd import api
+from pylxd import exceptions as lxd_exceptions
+
+
+def upload_image(image):
+    alias = '{}/{}/{}/{}'.format(image['os'],
+                                 image['release'],
+                                 image['arch'],
+                                 image['variant'])
+    lxd = api.API()
+    imgs = api.API(host='images.linuxcontainers.org')
+    d = imgs.alias_show(alias)
+
+    meta = d[1]['metadata']
+    tgt = meta['target']
+
+    try:
+        lxd.alias_update(meta)
+    except lxd_exceptions.APIError as ex:
+        if ex.status_code == 404:
+            lxd.alias_create(meta)
+
+    return tgt
+
+
+def delete_image(image):
+    lxd = api.API()
+    lxd.image_delete(image)
diff --git a/pylxd/tests/__init__.py b/pylxd/tests/__init__.py
deleted file mode 100644
index 4780a2b..0000000
--- a/pylxd/tests/__init__.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import data
-from ddt import unpack
-import unittest
-
-from pylxd import api
-
-
-class LXDAPITestBase(unittest.TestCase):
-
-    def setUp(self):
-        super(LXDAPITestBase, self).setUp()
-        self.lxd = api.API()
-
-
-def annotated_data(*args):
-    class List(list):
-        pass
-
-    new_args = []
-
-    for arg in args:
-        new_arg = List(arg)
-        new_arg.__name__ = arg[0]
-        new_args.append(new_arg)
-
-    return lambda func: data(*new_args)(unpack(func))
diff --git a/pylxd/tests/fake_api.py b/pylxd/tests/fake_api.py
deleted file mode 100644
index 849246e..0000000
--- a/pylxd/tests/fake_api.py
+++ /dev/null
@@ -1,272 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-
-def fake_standard_return():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {}
-    }
-
-
-def fake_host():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-                "api_compat": 1,
-                "auth": "trusted",
-                "config": {},
-                "environment": {
-                    "backing_fs": "ext4",
-                    "driver": "lxc",
-                    "kernel_version": "3.19.0-22-generic",
-                    "lxc_version": "1.1.2",
-                    "lxd_version": "0.12"
-                }
-        }
-    }
-
-
-def fake_image_list_empty():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": []
-    }
-
-
-def fake_image_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": ['/1.0/images/trusty']
-    }
-
-
-def fake_image_info():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-            "aliases": [
-                {
-                    "target": "ubuntu",
-                    "description": "ubuntu"
-                }
-            ],
-            "architecture": 2,
-            "fingerprint": "04aac4257341478b49c25d22cea8a6ce"
-                           "0489dc6c42d835367945e7596368a37f",
-            "filename": "",
-            "properties": {},
-            "public": 0,
-            "size": 67043148,
-            "created_at": 0,
-            "expires_at": 0,
-            "uploaded_at": 1435669853
-        }
-    }
-
-
-def fake_alias():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-                "target": "ubuntu",
-                "description": "ubuntu"
-        }
-    }
-
-
-def fake_alias_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/images/aliases/ubuntu"
-        ]
-    }
-
-
-def fake_container_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/containers/trusty-1"
-        ]
-    }
-
-
-def fake_container_state(status):
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-            "status": status
-        }
-    }
-
-
-def fake_container_log():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-            "log": "fake log"
-        }
-    }
-
-
-def fake_container_migrate():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "operation": "/1.0/operations/1234",
-        "metadata": {
-            "control": "fake_control",
-            "fs": "fake_fs",
-            "criu": "fake_criu",
-        }
-    }
-
-
-def fake_snapshots_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/containers/trusty-1/snapshots/first"
-        ]
-    }
-
-
-def fake_certificate_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/certificates/ABCDEF01"
-        ]
-    }
-
-
-def fake_certificate():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-            "type": "client",
-            "certificate": "ABCDEF01"
-        }
-    }
-
-
-def fake_profile_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/profiles/fake-profile"
-        ]
-    }
-
-
-def fake_profile():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": {
-            "name": "fake-profile",
-            "config": {
-                "resources.memory": "2GB",
-                "network.0.bridge": "lxcbr0"
-            }
-        }
-    }
-
-
-def fake_operation_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/operations/1234"
-        ]
-    }
-
-
-def fake_operation():
-    return {
-        "type": "async",
-        "status": "OK",
-        "status_code": 100,
-        "operation": "/1.0/operation/1234",
-        "metadata": {
-            "created_at": "2015-06-09T19:07:24.379615253-06:00",
-            "updated_at": "2015-06-09T19:07:23.379615253-06:00",
-            "status": "Running",
-            "status_code": 103,
-            "resources": {
-                "containers": ["/1.0/containers/1"]
-            },
-            "metadata": {},
-            "may_cancel": True
-        }
-    }
-
-
-def fake_network_list():
-    return {
-        "type": "sync",
-        "status": "Success",
-        "status_code": 200,
-        "metadata": [
-            "/1.0/networks/lxcbr0"
-        ]
-    }
-
-
-def fake_network():
-    return {
-        "type": "async",
-        "status": "OK",
-        "status_code": 100,
-        "operation": "/1.0/operation/1234",
-        "metadata": {
-            "name": "lxcbr0",
-            "type": "bridge",
-            "members": ["/1.0/containers/trusty-1"]
-        }
-    }
diff --git a/pylxd/tests/test_certificate.py b/pylxd/tests/test_certificate.py
deleted file mode 100644
index 090944b..0000000
--- a/pylxd/tests/test_certificate.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import ddt
-import json
-import mock
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
-class LXDAPICertificateTest(LXDAPITestBase):
-
-    def test_list_certificates(self):
-        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
-            ms.return_value = ('200', fake_api.fake_certificate_list())
-            self.assertEqual(
-                ['ABCDEF01'],
-                self.lxd.certificate_list())
-            ms.assert_called_with('GET',
-                                  '/1.0/certificates')
-
-    def test_certificate_show(self):
-        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
-            ms.return_value = ('200', fake_api.fake_certificate())
-            self.assertEqual(
-                ms.return_value, self.lxd.certificate_show('ABCDEF01'))
-            ms.assert_called_with('GET',
-                                  '/1.0/certificates/ABCDEF01')
-
-    @annotated_data(
-        ('delete', 'DELETE', '/ABCDEF01'),
-        ('create', 'POST', '', (json.dumps('ABCDEF01'),)),
-    )
-    def test_certificate_operations(self, method, http, path, call_args=()):
-        with mock.patch.object(connection.LXDConnection, 'get_status') as ms:
-            ms.return_value = True
-            self.assertTrue(
-                getattr(self.lxd, 'certificate_' + method)('ABCDEF01'))
-            ms.assert_called_with(http,
-                                  '/1.0/certificates' + path,
-                                  *call_args)
diff --git a/pylxd/tests/test_client.py b/pylxd/tests/test_client.py
deleted file mode 100644
index 821c59d..0000000
--- a/pylxd/tests/test_client.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright (c) 2016 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-"""Tests for pylxd.client."""
-import unittest
-
-import mock
-
-from pylxd import client
-
-
-class Test_APINode(unittest.TestCase):
-    """Tests for pylxd.client._APINode."""
-    ROOT = 'http://lxd/api'
-
-    def test_getattr(self):
-        """`__getattr__` returns a nested node."""
-        lxd = client._APINode(self.ROOT)
-
-        self.assertEqual('{}/fake'.format(self.ROOT), lxd.fake._api_endpoint)
-
-    def test_getattr_nested(self):
-        """Nested objects return a more detailed path."""
-        lxd = client._APINode(self.ROOT)  # NOQA
-
-        self.assertEqual(
-            '{}/fake/path'.format(self.ROOT),
-            lxd.fake.path._api_endpoint)
-
-    def test_getitem(self):
-        """`__getitem__` enables dynamic url parts."""
-        lxd = client._APINode(self.ROOT)  # NOQA
-
-        self.assertEqual(
-            '{}/fake/path'.format(self.ROOT),
-            lxd.fake['path']._api_endpoint)
-
-    def test_getitem_integer(self):
-        """`__getitem__` with an integer allows dynamic integer url parts."""
-        lxd = client._APINode(self.ROOT)  # NOQA
-
-        self.assertEqual(
-            '{}/fake/0'.format(self.ROOT),
-            lxd.fake[0]._api_endpoint)
-
-    @mock.patch('pylxd.client.requests.get')
-    def test_get(self, _get):
-        """`get` will make a request to the smart url."""
-        lxd = client._APINode(self.ROOT)
-
-        lxd.fake.get()
-
-        _get.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
-
-    @mock.patch('pylxd.client.requests.post')
-    def test_post(self, _post):
-        """`post` will POST to the smart url."""
-        lxd = client._APINode(self.ROOT)
-
-        lxd.fake.post()
-
-        _post.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
-
-    @mock.patch('pylxd.client.requests.put')
-    def test_put(self, _put):
-        """`put` will PUT to the smart url."""
-        lxd = client._APINode(self.ROOT)
-
-        lxd.fake.put()
-
-        _put.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
-
-    @mock.patch('pylxd.client.requests.delete')
-    def test_delete(self, _delete):
-        """`delete` will DELETE to the smart url."""
-        lxd = client._APINode(self.ROOT)
-
-        lxd.fake.delete()
-
-        _delete.assert_called_once_with('{}/{}'.format(self.ROOT, 'fake'))
diff --git a/pylxd/tests/test_connection.py b/pylxd/tests/test_connection.py
deleted file mode 100644
index 50e8ffd..0000000
--- a/pylxd/tests/test_connection.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import ddt
-import inspect
-import mock
-import six
-from six.moves import cStringIO
-from six.moves import http_client
-import socket
-import unittest
-
-from pylxd.deprecated import connection
-from pylxd.deprecated import exceptions
-from pylxd.tests import annotated_data
-
-if six.PY34:
-    from io import BytesIO
-
-
- at ddt
-class LXDInitConnectionTest(unittest.TestCase):
-
-    @mock.patch('socket.socket')
-    @mock.patch.object(http_client.HTTPConnection, '__init__')
-    def test_http_connection(self, mc, ms):
-        conn = connection.UnixHTTPConnection('/', 'host', 1234)
-        if six.PY34:
-            mc.assert_called_once_with(
-                conn, 'host', port=1234, timeout=None)
-        else:
-            mc.assert_called_once_with(
-                conn, 'host', port=1234, strict=None, timeout=None)
-        conn.connect()
-        ms.assert_called_once_with(socket.AF_UNIX, socket.SOCK_STREAM)
-        ms.return_value.connect.assert_called_once_with('/')
-
-    @mock.patch('os.environ', {'HOME': '/home/foo'})
-    @mock.patch('ssl.wrap_socket')
-    @mock.patch('socket.create_connection')
-    def test_https_connection(self, ms, ml):
-        conn = connection.HTTPSConnection('host', 1234)
-        with mock.patch.object(conn, '_tunnel') as mc:
-            conn.connect()
-            self.assertFalse(mc.called)
-            ms.assert_called_once_with(
-                ('host', 1234), socket._GLOBAL_DEFAULT_TIMEOUT, None)
-            ml.assert_called_once_with(
-                ms.return_value,
-                certfile='/home/foo/.config/lxc/client.crt',
-                keyfile='/home/foo/.config/lxc/client.key',
-                ssl_version=connection.DEFAULT_TLS_VERSION,
-            )
-
-    @mock.patch('os.environ', {'HOME': '/home/foo'})
-    @mock.patch('ssl.wrap_socket')
-    @mock.patch('socket.create_connection')
-    def test_https_proxy_connection(self, ms, ml):
-        conn = connection.HTTPSConnection('host', 1234)
-        conn._tunnel_host = 'host'
-        with mock.patch.object(conn, '_tunnel') as mc:
-            conn.connect()
-            self.assertTrue(mc.called)
-            ms.assert_called_once_with(
-                ('host', 1234), socket._GLOBAL_DEFAULT_TIMEOUT, None)
-            ml.assert_called_once_with(
-                ms.return_value,
-                certfile='/home/foo/.config/lxc/client.crt',
-                keyfile='/home/foo/.config/lxc/client.key',
-                ssl_version=connection.DEFAULT_TLS_VERSION)
-
-    @mock.patch('pylxd.deprecated.connection.HTTPSConnection')
-    @mock.patch('pylxd.deprecated.connection.UnixHTTPConnection')
-    @annotated_data(
-        ('unix', (None,), {}, '/var/lib/lxd/unix.socket'),
-        ('unix_path', (None,),
-         {'LXD_DIR': '/fake/'}, '/fake/unix.socket'),
-        ('https', ('host',), {}, ''),
-        ('https_port', ('host', 1234), {}, ''),
-    )
-    def test_get_connection(self, mode, args, env, path, mc, ms):
-        with mock.patch('os.environ', env):
-            conn = connection.LXDConnection(*args).get_connection()
-            if mode.startswith('unix'):
-                self.assertEqual(mc.return_value, conn)
-                mc.assert_called_once_with(path)
-            elif mode.startswith('https'):
-                self.assertEqual(ms.return_value, conn)
-                ms.assert_called_once_with(
-                    args[0], len(args) == 2 and args[1] or 8443)
-
-
-class FakeResponse(object):
-
-    def __init__(self, status, data):
-        self.status = status
-        if six.PY34:
-            self.read = BytesIO(six.b(data)).read
-        else:
-            self.read = cStringIO(data).read
-
-
- at ddt
- at mock.patch('pylxd.deprecated.connection.LXDConnection.get_connection')
-class LXDConnectionTest(unittest.TestCase):
-
-    def setUp(self):
-        super(LXDConnectionTest, self).setUp()
-        self.conn = connection.LXDConnection()
-
-    @annotated_data(
-        ('null', (200, '{}'), exceptions.PyLXDException),
-        ('200', (200, '{"foo": "bar"}'), (200, {'foo': 'bar'})),
-        ('202', (202, '{"status_code": 100}'), (202, {'status_code': 100})),
-        ('500', (500, '{"foo": "bar"}'), exceptions.APIError),
-    )
-    def test_get_object(self, tag, effect, result, mg):
-        mg.return_value.getresponse.return_value = FakeResponse(*effect)
-        if inspect.isclass(result):
-            self.assertRaises(result, self.conn.get_object)
-        else:
-            self.assertEqual(result, self.conn.get_object())
-
-    @annotated_data(
-        ('null', (200, '{}'), exceptions.PyLXDException),
-        ('200', (200, '{"foo": "bar"}'), True),
-        ('202', (202, '{"status_code": 100}'), True),
-        ('200', (200, '{"error": "bar"}'), exceptions.APIError),
-        ('500', (500, '{"foo": "bar"}'), False),
-    )
-    def test_get_status(self, tag, effect, result, mg):
-        mg.return_value.getresponse.return_value = FakeResponse(*effect)
-        if inspect.isclass(result):
-            self.assertRaises(result, self.conn.get_status)
-        else:
-            self.assertEqual(result, self.conn.get_status())
-
-    @annotated_data(
-        ('null', (200, ''), exceptions.PyLXDException),
-        ('200', (200, '{"foo": "bar"}'), six.b('{"foo": "bar"}')),
-        ('500', (500, '{"foo": "bar"}'),
-         exceptions.PyLXDException),
-    )
-    def test_get_raw(self, tag, effect, result, mg):
-        mg.return_value.getresponse.return_value = FakeResponse(*effect)
-        if inspect.isclass(result):
-            self.assertRaises(result, self.conn.get_raw)
-        else:
-            self.assertEqual(result, self.conn.get_raw())
-
-    @mock.patch('pylxd.deprecated.connection.WebSocketClient')
-    @annotated_data(
-        ('fake_host', 'wss://fake_host:8443'),
-        (None, 'ws+unix:///var/lib/lxd/unix.socket')
-    )
-    def test_get_ws(self, host, result, mock_ws, _):
-        conn = connection.LXDConnection(host)
-
-        conn.get_ws('/fake/path')
-
-        mock_ws.assert_has_calls([mock.call(result), mock.call().connect()])
diff --git a/pylxd/tests/test_container.py b/pylxd/tests/test_container.py
deleted file mode 100644
index 0385300..0000000
--- a/pylxd/tests/test_container.py
+++ /dev/null
@@ -1,222 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from collections import OrderedDict
-from ddt import ddt
-import json
-import mock
-import tempfile
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=('200', fake_api.fake_operation()))
-class LXDAPIContainerTestObject(LXDAPITestBase):
-
-    def test_list_containers(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_list())
-        self.assertEqual(
-            ['trusty-1'],
-            self.lxd.container_list())
-        ms.assert_called_once_with('GET',
-                                   '/1.0/containers')
-
-    @annotated_data(
-        ('STOPPED', False),
-        ('STOPPING', False),
-        ('ABORTING', False),
-        ('RUNNING', True),
-        ('STARTING', True),
-        ('FREEZING', True),
-        ('FROZEN', True),
-        ('THAWED', True),
-    )
-    def test_container_running(self, status, running, ms):
-        with mock.patch.object(connection.LXDConnection, 'get_object') as ms:
-            ms.return_value = ('200', fake_api.fake_container_state(status))
-            self.assertEqual(running, self.lxd.container_running('trusty-1'))
-            ms.assert_called_once_with('GET',
-                                       '/1.0/containers/trusty-1/state')
-
-    def test_container_init(self, ms):
-        self.assertEqual(ms.return_value, self.lxd.container_init('fake'))
-        ms.assert_called_once_with('POST',
-                                   '/1.0/containers',
-                                   '"fake"')
-
-    def test_container_update(self, ms):
-        self.assertEqual(ms.return_value,
-                         self.lxd.container_update('trusty-1',
-                                                   'fake'))
-        ms.assert_called_once_with('PUT',
-                                   '/1.0/containers/trusty-1',
-                                   '"fake"')
-
-    def test_container_state(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_state('RUNNING'))
-        self.assertEqual(ms.return_value, self.lxd.container_state('trusty-1'))
-        ms.assert_called_with('GET',
-                              '/1.0/containers/trusty-1/state')
-
-    @annotated_data(
-        ('start', 'start'),
-        ('stop', 'stop'),
-        ('suspend', 'freeze'),
-        ('resume', 'unfreeze'),
-        ('reboot', 'restart'),
-    )
-    def test_container_actions(self, method, action, ms):
-        self.assertEqual(
-            ms.return_value,
-            getattr(self.lxd, 'container_' + method)('trusty-1', 30))
-        ms.assert_called_once_with('PUT',
-                                   '/1.0/containers/trusty-1/state',
-                                   json.dumps({'action': action,
-                                               'force': True,
-                                               'timeout': 30, }))
-
-    def test_container_destroy(self, ms):
-        self.assertEqual(
-            ms.return_value, self.lxd.container_destroy('trusty-1'))
-        ms.assert_called_once_with('DELETE',
-                                   '/1.0/containers/trusty-1')
-
-    def test_container_log(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_log())
-        self.assertEqual(
-            'fake log', self.lxd.get_container_log('trusty-1'))
-        ms.assert_called_once_with('GET',
-                                   '/1.0/containers/trusty-1?log=true')
-
-    def test_container_config(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_state('fake'))
-        self.assertEqual(
-            {'status': 'fake'}, self.lxd.get_container_config('trusty-1'))
-        ms.assert_called_once_with('GET',
-                                   '/1.0/containers/trusty-1?log=false')
-
-    def test_container_info(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_state('fake'))
-        self.assertEqual(
-            {'status': 'fake'}, self.lxd.container_info('trusty-1'))
-        ms.assert_called_once_with('GET',
-                                   '/1.0/containers/trusty-1/state')
-
-    def test_container_migrate(self, ms):
-        ms.return_value = ('200', fake_api.fake_container_migrate())
-        self.assertEqual(
-            {'control': 'fake_control',
-             'criu': 'fake_criu',
-             'fs': 'fake_fs',
-             'operation': '1234'},
-            self.lxd.container_migrate('trusty-1'))
-        ms.assert_called_once_with('POST',
-                                   '/1.0/containers/trusty-1',
-                                   '{"migration": true}')
-
-    def test_container_publish(self, ms):
-        ms.return_value = ('200', fake_api.fake_operation())
-        self.assertEqual(
-            ms.return_value, self.lxd.container_publish('trusty-1'))
-        ms.assert_called_once_with('POST',
-                                   '/1.0/images',
-                                   '"trusty-1"')
-
-    def test_container_put_file(self, ms):
-        temp_file = tempfile.NamedTemporaryFile()
-        ms.return_value = ('200', fake_api.fake_standard_return())
-        self.assertEqual(
-            ms.return_value, self.lxd.put_container_file('trusty-1',
-                                                         temp_file.name,
-                                                         'dst_file'))
-        ms.assert_called_once_with(
-            'POST',
-            '/1.0/containers/trusty-1/files?path=dst_file',
-            body=b'',
-            headers={'X-LXD-gid': 0, 'X-LXD-mode': 0o644, 'X-LXD-uid': 0})
-
-    def test_list_snapshots(self, ms):
-        ms.return_value = ('200', fake_api.fake_snapshots_list())
-        self.assertEqual(
-            ['/1.0/containers/trusty-1/snapshots/first'],
-            self.lxd.container_snapshot_list('trusty-1'))
-        ms.assert_called_once_with('GET',
-                                   '/1.0/containers/trusty-1/snapshots')
-
-    @annotated_data(
-        ('create', 'POST', '', ('fake config',), ('"fake config"',)),
-        ('info', 'GET', '/first', ('first',), ()),
-        ('rename', 'POST', '/first',
-         ('first', 'fake config'), ('"fake config"',)),
-        ('delete', 'DELETE', '/first', ('first',), ()),
-    )
-    def test_snapshot_operations(self, method, http, path,
-                                 args, call_args, ms):
-        self.assertEqual(
-            ms.return_value,
-            getattr(self.lxd,
-                    'container_snapshot_' + method)('trusty-1', *args))
-        ms.assert_called_once_with(http,
-                                   '/1.0/containers/trusty-1/snapshots' +
-                                   path,
-                                   *call_args)
-
-    def test_container_run_command(self, ms):
-        data = OrderedDict((
-            ('command', ['/fake/command']),
-            ('interactive', False),
-            ('wait-for-websocket', False),
-            ('environment', {'FAKE_ENV': 'fake'})
-        ))
-
-        self.assertEqual(
-            ms.return_value,
-            self.lxd.container_run_command('trusty-1', *data.values()))
-        self.assertEqual(1, ms.call_count)
-        self.assertEqual(
-            ms.call_args[0][:2],
-            ('POST', '/1.0/containers/trusty-1/exec'))
-        self.assertEqual(
-            json.loads(ms.call_args[0][2]),
-            dict(data)
-        )
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=('200', fake_api.fake_container_list()))
-class LXDAPIContainerTestStatus(LXDAPITestBase):
-
-    def test_container_defined(self, ms):
-        self.assertTrue(self.lxd.container_defined('trusty-1'))
-        ms.assert_called_once_with('GET', '/1.0/containers')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_raw',
-                   return_value='fake contents')
-class LXDAPIContainerTestRaw(LXDAPITestBase):
-
-    def test_container_file(self, ms):
-        self.assertEqual(
-            'fake contents', self.lxd.get_container_file('trusty-1',
-                                                         '/file/name'))
-        ms.assert_called_once_with(
-            'GET', '/1.0/containers/trusty-1/files?path=/file/name')
diff --git a/pylxd/tests/test_host.py b/pylxd/tests/test_host.py
deleted file mode 100644
index 80e2ad4..0000000
--- a/pylxd/tests/test_host.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import data
-from ddt import ddt
-import mock
-
-from pylxd.deprecated import connection
-from pylxd.deprecated import exceptions
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=('200', fake_api.fake_host()))
-class LXDAPIHostTestObject(LXDAPITestBase):
-
-    def test_get_host_info(self, ms):
-        result = self.lxd.host_info()
-        self.assertEqual(result, {
-            'lxd_api_compat_level': 1,
-            'lxd_trusted_host': True,
-            'lxd_backing_fs': 'ext4',
-            'lxd_driver': 'lxc',
-            'lxd_version': 0.12,
-            'lxc_version': '1.1.2',
-            'kernel_version': '3.19.0-22-generic',
-        })
-        ms.assert_called_once_with('GET', '/1.0')
-
-    host_data = (
-        ('lxd_api_compat', 1),
-        ('lxd_host_trust', True),
-        ('lxd_backing_fs', 'ext4'),
-        ('lxd_driver', 'lxc'),
-        ('lxc_version', '1.1.2'),
-        ('lxd_version', 0.12),
-        ('kernel_version', '3.19.0-22-generic'),
-    )
-
-    @annotated_data(*host_data)
-    def test_get_host_data(self, method, expected, ms):
-        result = getattr(self.lxd, 'get_' + method)(data=None)
-        self.assertEqual(expected, result)
-        ms.assert_called_once_with('GET', '/1.0')
-
-    @annotated_data(*host_data)
-    def test_get_host_data_fail(self, method, expected, ms):
-        ms.side_effect = exceptions.PyLXDException
-        result = getattr(self.lxd, 'get_' + method)(data=None)
-        self.assertEqual(None, result)
-        ms.assert_called_once_with('GET', '/1.0')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_status')
-class LXDAPIHostTestStatus(LXDAPITestBase):
-
-    @data(True, False)
-    def test_get_host_ping(self, value, ms):
-        ms.return_value = value
-        self.assertEqual(value, self.lxd.host_ping())
-        ms.assert_called_once_with('GET', '/1.0')
-
-    def test_get_host_ping_fail(self, ms):
-        ms.side_effect = Exception
-        self.assertRaises(exceptions.PyLXDException, self.lxd.host_ping)
-        ms.assert_called_once_with('GET', '/1.0')
diff --git a/pylxd/tests/test_image.py b/pylxd/tests/test_image.py
deleted file mode 100644
index 93b33f1..0000000
--- a/pylxd/tests/test_image.py
+++ /dev/null
@@ -1,241 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import datetime
-from ddt import ddt
-import mock
-from six.moves import builtins
-from six.moves import cStringIO
-import unittest
-
-from pylxd.deprecated import connection
-from pylxd.deprecated import exceptions
-from pylxd.deprecated import image
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=('200', fake_api.fake_image_info()))
-class LXDAPIImageTestObject(LXDAPITestBase):
-
-    list_data = (
-        ('list', (), ()),
-        ('search', ({'foo': 'bar'},), ('foo=bar',)),
-    )
-
-    @annotated_data(*list_data)
-    def test_list_images(self, method, args, call_args, ms):
-        ms.return_value = ('200', fake_api.fake_image_list())
-        self.assertEqual(
-            ['trusty'], getattr(self.lxd, 'image_' + method)(*args))
-        ms.assert_called_once_with('GET', '/1.0/images', *call_args)
-
-    @annotated_data(*list_data)
-    def test_list_images_fail(self, method, args, call_args, ms):
-        ms.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException,
-                          getattr(self.lxd, 'image_' + method),
-                          *args)
-        ms.assert_called_once_with('GET', '/1.0/images', *call_args)
-
-    @annotated_data(
-        (True, (('200', fake_api.fake_image_info()),)),
-        (False, exceptions.APIError("404", 404)),
-    )
-    def test_image_defined(self, expected, side_effect, ms):
-        ms.side_effect = side_effect
-        self.assertEqual(expected, self.lxd.image_defined('test-image'))
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    @annotated_data(
-        ('APIError', exceptions.APIError("500", 500), exceptions.APIError),
-        ('PyLXDException', exceptions.PyLXDException,
-         exceptions.PyLXDException)
-    )
-    def test_image_defined_fail(self, tag, side_effect, expected, ms):
-        ms.side_effect = side_effect
-        self.assertRaises(expected,
-                          self.lxd.image_defined, ('test-image',))
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    def test_image_info(self, ms):
-        self.assertEqual({
-            'image_upload_date': (datetime.datetime
-                                  .fromtimestamp(1435669853)
-                                  .strftime('%Y-%m-%d %H:%M:%S')),
-            'image_created_date': 'Unknown',
-            'image_expires_date': 'Unknown',
-            'image_public': False,
-            'image_size': '63MB',
-            'image_fingerprint': '04aac4257341478b49c25d22cea8a6ce'
-                                 '0489dc6c42d835367945e7596368a37f',
-            'image_architecture': 'x86_64',
-        }, self.lxd.image_info('test-image'))
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    def test_image_info_fail(self, ms):
-        ms.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException,
-                          self.lxd.image_info, ('test-image',))
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    dates_data = (
-        ('upload', (datetime.datetime.fromtimestamp(1435669853)
-                    .strftime('%Y-%m-%d %H:%M:%S'))),
-        ('create', 'Unknown'),
-        ('expire', 'Unknown'),
-    )
-
-    @annotated_data(*dates_data)
-    def test_image_date(self, method, expected, ms):
-        self.assertEqual(expected, getattr(
-            self.lxd, 'image_{}_date'.format(method))('test-image',
-                                                      data=None))
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    @annotated_data(*dates_data)
-    def test_image_date_fail(self, method, expected, ms):
-        ms.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException, getattr(
-            self.lxd,
-            'image_{}_date'.format(method)),
-            'test-image',
-            data=None)
-        ms.assert_called_once_with('GET', '/1.0/images/test-image')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
-class LXDAPIImageTestStatus(LXDAPITestBase):
-    operations_data = (
-        ('delete', 'DELETE', '/test-image', ('test-image',), ()),
-        ('update', 'PUT', '/test-image', ('test-image', 'fake',), ('"fake"',)),
-        ('rename', 'POST', '/test-image',
-         ('test-image', 'fake',), ('"fake"',)),
-    )
-
-    @annotated_data(*operations_data)
-    def test_image_operations(self, method, http, path, args, call_args, ms):
-        self.assertTrue(
-            getattr(self.lxd, 'image_' + method)(*args))
-        ms.assert_called_once_with(
-            http,
-            '/1.0/images' + path,
-            *call_args
-        )
-
-    @annotated_data(*operations_data)
-    def test_image_operations_fail(self, method, http, path,
-                                   args, call_args, ms):
-        ms.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException,
-                          getattr(self.lxd, 'image_' + method),
-                          *args)
-        ms.assert_called_once_with(
-            http,
-            '/1.0/images' + path,
-            *call_args
-        )
-
-
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=('200', fake_api.fake_image_info()))
-class LXDAPAPIImageTestUpload(LXDAPITestBase):
-    @mock.patch.object(builtins, 'open', return_value=cStringIO('fake'))
-    def test_image_upload_file(self, mo, ms):
-        self.assertTrue(self.lxd.image_upload(path='/fake/path'))
-        mo.assert_called_once_with('/fake/path', 'rb')
-        ms.assert_called_once_with('POST', '/1.0/images', 'fake', {})
-
-
- at mock.patch.object(connection.LXDConnection, 'get_raw')
-class LXDAPIImageTestRaw(LXDAPITestBase):
-
-    def test_image_export(self, ms):
-        ms.return_value = 'fake contents'
-        self.assertEqual('fake contents', self.lxd.image_export('fake'))
-        ms.assert_called_once_with('GET', '/1.0/images/fake/export')
-
-    def test_image_export_fail(self, ms):
-        ms.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException,
-                          self.lxd.image_export, 'fake')
-        ms.assert_called_once_with('GET', '/1.0/images/fake/export')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=(200, fake_api.fake_image_info()))
-class LXDAPIImageInfoTest(unittest.TestCase):
-
-    def setUp(self):
-        super(LXDAPIImageInfoTest, self).setUp()
-        self.image = image.LXDImage()
-
-    info_list = (
-        ('permission', False),
-        ('size', 63),
-        ('fingerprint', '04aac4257341478b49c25d22cea8a6ce'
-                        '0489dc6c42d835367945e7596368a37f'),
-        ('architecture', 'x86_64'),
-    )
-
-    @annotated_data(*info_list)
-    def test_info_no_data(self, method, expected, mc):
-        self.assertEqual(expected,
-                         (getattr(self.image, 'get_image_' + method)
-                          ('test-image', data=None)))
-        mc.assert_called_once_with('GET', '/1.0/images/test-image')
-
-    @annotated_data(*info_list)
-    def test_info_no_data_fail(self, method, expected, mc):
-        mc.side_effect = exceptions.PyLXDException
-        self.assertRaises(exceptions.PyLXDException,
-                          getattr(self.image, 'get_image_' + method),
-                          'test-image',
-                          data=None)
-
-    @annotated_data(
-        ('permission_true', 'permission', {'public': 0}, False),
-        ('permission_false', 'permission', {'public': 1}, True),
-        ('size', 'size', {'size': 52428800}, 50),
-        ('fingerprint', 'fingerprint', {'fingerprint': 'AAAA'}, 'AAAA'),
-        *[('architecture_' + v, 'architecture', {'architecture': k}, v)
-          for k, v in image.image_architecture.items()]
-    )
-    def test_info_data(self, tag, method, metadata, expected, mc):
-        self.assertEqual(
-            expected, getattr(self.image, 'get_image_' + method)
-            ('test-image', data=metadata))
-        self.assertFalse(mc.called)
-
-    @annotated_data(
-        ('permission', 'permission', {}, KeyError),
-        ('size', 'size', {'size': 0}, exceptions.ImageInvalidSize),
-        ('size', 'size', {'size': -1}, exceptions.ImageInvalidSize),
-        ('fingerprint', 'fingerprint', {}, KeyError),
-        ('architecture', 'architecture', {}, KeyError),
-        ('architecture_invalid', 'architecture',
-         {'architecture': -1}, KeyError)
-    )
-    def test_info_data_fail(self, tag, method, metadata, expected, mc):
-        self.assertRaises(expected,
-                          getattr(self.image, 'get_image_' + method),
-                          'test-image',
-                          data=metadata)
-        self.assertFalse(mc.called)
diff --git a/pylxd/tests/test_image_alias.py b/pylxd/tests/test_image_alias.py
deleted file mode 100644
index bccc44c..0000000
--- a/pylxd/tests/test_image_alias.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import data
-from ddt import ddt
-import mock
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object')
-class LXDAPIImageAliasTestObject(LXDAPITestBase):
-
-    def test_alias_list(self, ms):
-        ms.return_value = ('200', fake_api.fake_alias_list())
-        self.assertEqual(['ubuntu'], self.lxd.alias_list())
-        ms.assert_called_once_with('GET', '/1.0/images/aliases')
-
-    def test_alias_show(self, ms):
-        ms.return_value = ('200', fake_api.fake_alias())
-        self.assertEqual(
-            fake_api.fake_alias(), self.lxd.alias_show('fake')[1])
-        ms.assert_called_once_with('GET', '/1.0/images/aliases/fake')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_status')
-class LXDAPIImageAliasTestStatus(LXDAPITestBase):
-
-    @data(True, False)
-    def test_alias_defined(self, expected, ms):
-        ms.return_value = expected
-        self.assertEqual(expected, self.lxd.alias_defined('fake'))
-        ms.assert_called_once_with('GET', '/1.0/images/aliases/fake')
-
-    @annotated_data(
-        ('create', 'POST', '', ('fake',), ('"fake"',)),
-        ('update', 'PUT', '/test-alias',
-         ('test-alias', 'fake',), ('"fake"',)),
-        ('rename', 'POST', '/test-alias',
-         ('test-alias', 'fake',), ('"fake"',)),
-        ('delete', 'DELETE', '/test-alias', ('test-alias',), ()),
-    )
-    def test_alias_operations(self, method, http, path, args, call_args, ms):
-        self.assertTrue(getattr(self.lxd, 'alias_' + method)(*args))
-        ms.assert_called_once_with(
-            http,
-            '/1.0/images/aliases' + path,
-            *call_args
-        )
diff --git a/pylxd/tests/test_network.py b/pylxd/tests/test_network.py
deleted file mode 100644
index 65efdb6..0000000
--- a/pylxd/tests/test_network.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import ddt
-import mock
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=(200, fake_api.fake_network()))
-class LXDAPINetworkTest(LXDAPITestBase):
-
-    def test_list_networks(self, ms):
-        ms.return_value = ('200', fake_api.fake_network_list())
-        self.assertEqual(
-            ['lxcbr0'],
-            self.lxd.network_list())
-        ms.assert_called_with('GET',
-                              '/1.0/networks')
-
-    def test_network_show(self, ms):
-        self.assertEqual({
-            'network_name': 'lxcbr0',
-            'network_type': 'bridge',
-            'network_members': ['/1.0/containers/trusty-1'],
-        }, self.lxd.network_show('lxcbr0'))
-        ms.assert_called_with('GET',
-                              '/1.0/networks/lxcbr0')
-
-    @annotated_data(
-        ('name', 'lxcbr0'),
-        ('type', 'bridge'),
-        ('members', ['/1.0/containers/trusty-1']),
-    )
-    def test_network_data(self, method, expected, ms):
-        self.assertEqual(
-            expected, getattr(self.lxd,
-                              'network_show_' + method)('lxcbr0'))
-        ms.assert_called_with('GET',
-                              '/1.0/networks/lxcbr0')
diff --git a/pylxd/tests/test_operation.py b/pylxd/tests/test_operation.py
deleted file mode 100644
index 233bb0b..0000000
--- a/pylxd/tests/test_operation.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import datetime
-from ddt import ddt
-import mock
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=(200, fake_api.fake_operation()))
-class LXDAPIOperationTestObject(LXDAPITestBase):
-
-    def test_list_operations(self, ms):
-        ms.return_value = ('200', fake_api.fake_operation_list())
-        self.assertEqual(
-            ['/1.0/operations/1234'],
-            self.lxd.list_operations())
-        ms.assert_called_with('GET',
-                              '/1.0/operations')
-
-    def test_operation_info(self, ms):
-        ms.return_value = ('200', fake_api.fake_operation())
-        self.assertEqual(
-            ms.return_value, self.lxd.operation_info('/1.0/operations/1234'))
-        ms.assert_called_with('GET',
-                              '/1.0/operations/1234')
-
-    @annotated_data(
-        ('create_time',
-         datetime.datetime.utcfromtimestamp(1433876844)
-         .strftime('%Y-%m-%d %H:%M:%S')),
-        ('update_time',
-         datetime.datetime.utcfromtimestamp(1433876843)
-         .strftime('%Y-%m-%d %H:%M:%S')),
-        ('status', 'Running'),
-    )
-    def test_operation_show(self, method, expected, ms):
-        call = getattr(self.lxd, 'operation_show_' + method)
-        self.assertEqual(expected, call('/1.0/operations/1234'))
-        ms.assert_called_with('GET',
-                              '/1.0/operations/1234')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
-class LXDAPIOperationTestStatus(LXDAPITestBase):
-
-    @annotated_data(
-        ('operation_delete', 'DELETE', '', ()),
-        ('wait_container_operation', 'GET',
-         '/wait?status_code=200&timeout=30', ('200', '30')),
-    )
-    def test_operation_actions(self, method, http, path, args, ms):
-        self.assertTrue(
-            getattr(self.lxd, method)('/1.0/operations/1234', *args))
-        ms.assert_called_with(http,
-                              '/1.0/operations/1234' + path)
diff --git a/pylxd/tests/test_profiles.py b/pylxd/tests/test_profiles.py
deleted file mode 100644
index 1844986..0000000
--- a/pylxd/tests/test_profiles.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from ddt import data
-from ddt import ddt
-import mock
-
-from pylxd.deprecated import connection
-
-from pylxd.tests import annotated_data
-from pylxd.tests import fake_api
-from pylxd.tests import LXDAPITestBase
-
-
- at mock.patch.object(connection.LXDConnection, 'get_object',
-                   return_value=(200, fake_api.fake_profile()))
-class LXDAPIProfilesTestObject(LXDAPITestBase):
-
-    def test_list_profiles(self, ms):
-        ms.return_value = ('200', fake_api.fake_profile_list())
-        self.assertEqual(
-            ['fake-profile'],
-            self.lxd.profile_list())
-        ms.assert_called_with('GET',
-                              '/1.0/profiles')
-
-    def test_profile_show(self, ms):
-        self.assertEqual(
-            ms.return_value, self.lxd.profile_show('fake-profile'))
-        ms.assert_called_with('GET',
-                              '/1.0/profiles/fake-profile')
-
-
- at ddt
- at mock.patch.object(connection.LXDConnection, 'get_status', return_value=True)
-class LXDAPIProfilesTestStatus(LXDAPITestBase):
-
-    @data(True, False)
-    def test_profile_defined(self, defined, ms):
-        ms.return_value = defined
-        self.assertEqual(defined, self.lxd.profile_defined('fake-profile'))
-        ms.assert_called_with('GET',
-                              '/1.0/profiles/fake-profile')
-
-    @annotated_data(
-        ('create', 'POST', '', ('fake config',), ('"fake config"',)),
-        ('update', 'PUT', '/fake-profile',
-         ('fake-profile', 'fake config',), ('"fake config"',)),
-        ('rename', 'POST', '/fake-profile',
-         ('fake-profile', 'fake config',), ('"fake config"',)),
-        ('delete', 'DELETE', '/fake-profile', ('fake-profile',), ()),
-    )
-    def test_profile_operations(self, method, http, path, args, call_args, ms):
-        self.assertTrue(
-            getattr(self.lxd, 'profile_' + method)(*args))
-        ms.assert_called_with(http,
-                              '/1.0/profiles' + path,
-                              *call_args)
diff --git a/pylxd/tests/utils.py b/pylxd/tests/utils.py
deleted file mode 100644
index ec424bf..0000000
--- a/pylxd/tests/utils.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (c) 2015 Canonical Ltd
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from pylxd import api
-from pylxd import exceptions as lxd_exceptions
-
-
-def upload_image(image):
-    alias = '{}/{}/{}/{}'.format(image['os'],
-                                 image['release'],
-                                 image['arch'],
-                                 image['variant'])
-    lxd = api.API()
-    imgs = api.API(host='images.linuxcontainers.org')
-    d = imgs.alias_show(alias)
-
-    meta = d[1]['metadata']
-    tgt = meta['target']
-
-    try:
-        lxd.alias_update(meta)
-    except lxd_exceptions.APIError as ex:
-        if ex.status_code == 404:
-            lxd.alias_create(meta)
-
-    return tgt
-
-
-def delete_image(image):
-    lxd = api.API()
-    lxd.image_delete(image)


More information about the lxc-devel mailing list