[lxc-devel] [pylxd/master] Add `NotFound` and `exists`
rockstar on Github
lxc-bot at linuxcontainers.org
Thu Nov 24 18:34:09 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 774 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161124/09236aae/attachment.bin>
-------------- next part --------------
From 1fe83e913c9a054fc5e413be485ab7644a7596b3 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Thu, 24 Nov 2016 11:25:15 -0700
Subject: [PATCH 1/2] Add NotFound exception in the case of 404
---
pylxd/client.py | 2 ++
pylxd/exceptions.py | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/pylxd/client.py b/pylxd/client.py
index 606f11f..b4470d0 100644
--- a/pylxd/client.py
+++ b/pylxd/client.py
@@ -64,6 +64,8 @@ def _assert_response(
user.
"""
if response.status_code not in allowed_status_codes:
+ if response.status_code == 404:
+ raise exceptions.NotFound(response)
raise exceptions.LXDAPIException(response)
# In the case of streaming, we can't validate the json the way we
diff --git a/pylxd/exceptions.py b/pylxd/exceptions.py
index d5b6b5e..a8b27f6 100644
--- a/pylxd/exceptions.py
+++ b/pylxd/exceptions.py
@@ -26,5 +26,9 @@ def __str__(self):
return self.response.content.decode('utf-8')
+class NotFound(LXDAPIException):
+ """An exception raised when an object is not found."""
+
+
class ClientConnectionFailed(Exception):
"""An exception raised when the Client connection fails."""
From 4514e8f551d57c63b86662445d8180b0935f3d7d Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Thu, 24 Nov 2016 11:26:25 -0700
Subject: [PATCH 2/2] Add `exists` to `Container`, `Image`, and `Profile`
---
pylxd/models/_model.py | 2 ++
pylxd/models/container.py | 9 +++++++++
pylxd/models/image.py | 16 ++++++++++++++++
pylxd/models/profile.py | 9 +++++++++
pylxd/tests/models/test_container.py | 24 ++++++++++++++++++++++++
pylxd/tests/models/test_image.py | 29 +++++++++++++++++++++++++++++
pylxd/tests/models/test_profile.py | 22 ++++++++++++++++++++++
7 files changed, 111 insertions(+)
diff --git a/pylxd/models/_model.py b/pylxd/models/_model.py
index 7307a0d..24900ae 100644
--- a/pylxd/models/_model.py
+++ b/pylxd/models/_model.py
@@ -15,6 +15,7 @@
import six
+from pylxd import exceptions
from pylxd.models.operation import Operation
@@ -96,6 +97,7 @@ class Model(object):
the instance is marked as dirty. `save` will save the changes
to the server.
"""
+ NotFound = exceptions.NotFound
__slots__ = ['client', '__dirty__']
def __init__(self, client, **kwargs):
diff --git a/pylxd/models/container.py b/pylxd/models/container.py
index 27552f8..dbedc6c 100644
--- a/pylxd/models/container.py
+++ b/pylxd/models/container.py
@@ -91,6 +91,15 @@ def get(self, filepath):
return response.content
@classmethod
+ def exists(cls, client, name):
+ """Determine whether a container exists."""
+ try:
+ client.containers.get(name)
+ return True
+ except cls.NotFound:
+ return False
+
+ @classmethod
def get(cls, client, name):
"""Get a container by name."""
response = client.api.containers[name].get()
diff --git a/pylxd/models/image.py b/pylxd/models/image.py
index ac1c4fa..6c54e9f 100644
--- a/pylxd/models/image.py
+++ b/pylxd/models/image.py
@@ -58,6 +58,22 @@ def api(self):
return self.client.api.images[self.fingerprint]
@classmethod
+ def exists(cls, client, fingerprint, alias=False):
+ """Determine whether an image exists.
+
+ If `alias` is True, look up the image by its alias,
+ rather than its fingerprint.
+ """
+ try:
+ if alias:
+ client.images.get_by_alias(fingerprint)
+ else:
+ client.images.get(fingerprint)
+ return True
+ except cls.NotFound:
+ return False
+
+ @classmethod
def get(cls, client, fingerprint):
"""Get an image."""
response = client.api.images[fingerprint].get()
diff --git a/pylxd/models/profile.py b/pylxd/models/profile.py
index c5d564c..13f01e7 100644
--- a/pylxd/models/profile.py
+++ b/pylxd/models/profile.py
@@ -23,6 +23,15 @@ class Profile(model.Model):
devices = model.Attribute()
@classmethod
+ def exists(cls, client, name):
+ """Determine whether a profile exists."""
+ try:
+ client.profiles.get(name)
+ return True
+ except cls.NotFound:
+ return False
+
+ @classmethod
def get(cls, client, name):
"""Get a profile."""
response = client.api.profiles[name].get()
diff --git a/pylxd/tests/models/test_container.py b/pylxd/tests/models/test_container.py
index a32eb84..4fd15ac 100644
--- a/pylxd/tests/models/test_container.py
+++ b/pylxd/tests/models/test_container.py
@@ -72,6 +72,30 @@ def test_create(self):
self.assertEqual(config['name'], an_new_container.name)
+ def test_exists(self):
+ """A container exists."""
+ name = 'an-container'
+
+ self.assertTrue(models.Container.exists(self.client, name))
+
+ def test_not_exists(self):
+ """A container exists."""
+ def not_found(request, context):
+ context.status_code = 404
+ return json.dumps({
+ 'type': 'error',
+ 'error': 'Not found',
+ 'error_code': 404})
+ self.add_rule({
+ 'text': not_found,
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/containers/an-missing-container$', # NOQA
+ })
+
+ name = 'an-missing-container'
+
+ self.assertFalse(models.Container.exists(self.client, name))
+
def test_fetch(self):
"""A sync updates the properties of a container."""
an_container = models.Container(
diff --git a/pylxd/tests/models/test_image.py b/pylxd/tests/models/test_image.py
index 40cf853..7040a2d 100644
--- a/pylxd/tests/models/test_image.py
+++ b/pylxd/tests/models/test_image.py
@@ -62,6 +62,35 @@ def test_get_by_alias(self):
self.assertEqual(fingerprint, a_image.fingerprint)
+ def test_exists(self):
+ """An image is fetched."""
+ fingerprint = hashlib.sha256(b'').hexdigest()
+
+ self.assertTrue(models.Image.exists(self.client, fingerprint))
+
+ def test_exists_by_alias(self):
+ """An image is fetched."""
+ self.assertTrue(models.Image.exists(
+ self.client, 'an-alias', alias=True))
+
+ def test_not_exists(self):
+ """LXDAPIException is raised when the image isn't found."""
+ def not_found(request, context):
+ context.status_code = 404
+ return json.dumps({
+ 'type': 'error',
+ 'error': 'Not found',
+ 'error_code': 404})
+ self.add_rule({
+ 'text': not_found,
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
+ })
+
+ fingerprint = hashlib.sha256(b'').hexdigest()
+
+ self.assertFalse(models.Image.exists(self.client, fingerprint))
+
def test_all(self):
"""A list of all images is returned."""
images = models.Image.all(self.client)
diff --git a/pylxd/tests/models/test_profile.py b/pylxd/tests/models/test_profile.py
index 6a357aa..58b01bd 100644
--- a/pylxd/tests/models/test_profile.py
+++ b/pylxd/tests/models/test_profile.py
@@ -50,6 +50,28 @@ def error(request, context):
exceptions.LXDAPIException,
models.Profile.get, self.client, 'an-profile')
+ def test_exists(self):
+ name = 'an-profile'
+
+ self.assertTrue(models.Profile.exists(self.client, name))
+
+ def test_not_exists(self):
+ def not_found(request, context):
+ context.status_code = 404
+ return json.dumps({
+ 'type': 'error',
+ 'error': 'Not found',
+ 'error_code': 404})
+ self.add_rule({
+ 'text': not_found,
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/profiles/an-profile$',
+ })
+
+ name = 'an-profile'
+
+ self.assertFalse(models.Profile.exists(self.client, name))
+
def test_all(self):
"""A list of all profiles is returned."""
profiles = models.Profile.all(self.client)
More information about the lxc-devel
mailing list