[lxc-devel] [pylxd/master] Add image aliases support.
pcdummy on Github
lxc-bot at linuxcontainers.org
Mon Jul 25 16:56:49 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 432 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160725/cc5cb38f/attachment.bin>
-------------- next part --------------
From d7e482f1f402f8e7eca67c5f4458bf8915ccdd2f Mon Sep 17 00:00:00 2001
From: Rene Jochum <rene at jochums.at>
Date: Mon, 25 Jul 2016 18:55:09 +0200
Subject: [PATCH] Add image aliases support.
Signed-off-by: Rene Jochum <rene at jochums.at>
---
doc/source/images.rst | 3 ++
pylxd/image.py | 24 +++++++++-
pylxd/tests/mock_lxd.py | 50 +++++++++++++------
pylxd/tests/test_image.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 16 deletions(-)
diff --git a/doc/source/images.rst b/doc/source/images.rst
index 6c22152..574a7c8 100644
--- a/doc/source/images.rst
+++ b/doc/source/images.rst
@@ -49,6 +49,9 @@ Image methods
- `export` - Export the image. Returns binary data that is the
image itself.
+ - `add_alias` - Add an alias to the image.
+
+ - `delete_alias` - Remove an alias.
Examples
--------
diff --git a/pylxd/image.py b/pylxd/image.py
index 4cca19e..560a378 100644
--- a/pylxd/image.py
+++ b/pylxd/image.py
@@ -19,7 +19,7 @@
class Image(model.Model):
"""A LXD Image."""
- aliases = model.Attribute()
+ aliases = model.Attribute(readonly=True)
auto_update = model.Attribute()
architecture = model.Attribute()
cached = model.Attribute()
@@ -84,3 +84,25 @@ def export(self):
"""Export the image."""
response = self.api.export.get()
return response.content
+
+ def add_alias(self, name, description):
+ """Add an alias to the image."""
+ self.client.api.images.aliases.post(json={
+ 'description': description,
+ 'target': self.fingerprint,
+ 'name': name
+ })
+
+ # Update current aliases list
+ self.sync()
+
+ return self
+
+ def delete_alias(self, name, wait=False):
+ """Delete an alias from the image."""
+ self.client.api.images.aliases[name].delete()
+
+ # Update current aliases list
+ self.sync()
+
+ return self
diff --git a/pylxd/tests/mock_lxd.py b/pylxd/tests/mock_lxd.py
index 5dbea19..2947116 100644
--- a/pylxd/tests/mock_lxd.py
+++ b/pylxd/tests/mock_lxd.py
@@ -366,26 +366,12 @@ def profile_GET(request, context):
'url': r'^http://pylxd.test/1.0/images$',
},
{
- 'json': {
- 'type': 'sync',
- 'status': 'Success',
- 'status_code': 200,
- 'metadata': {
- 'name': 'an-alias',
- 'description': 'an-alias',
- 'target': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
- }
- },
- 'method': 'GET',
- 'url': r'^http://pylxd.test/1.0/images/aliases/an-alias$',
- },
- {
'text': json.dumps({
'type': 'sync',
'metadata': {
'aliases': [
{
- 'name': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
+ 'name': 'an-alias', # NOQA
'fingerprint': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
}
],
@@ -424,6 +410,40 @@ def profile_GET(request, context):
'url': r'^http://pylxd.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
},
+ # Image Aliases
+ {
+ 'json': {
+ 'type': 'sync',
+ 'status': 'Success',
+ 'status_code': 200,
+ 'metadata': {
+ 'name': 'an-alias',
+ 'description': 'an-alias',
+ 'target': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
+ }
+ },
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/images/aliases/an-alias$',
+ },
+ {
+ 'json': {
+ 'type': 'sync',
+ 'status': 'Success',
+ 'metadata': None
+ },
+ 'method': 'POST',
+ 'url': r'^http://pylxd.test/1.0/images/aliases$'
+ },
+ {
+ 'json': {
+ 'type': 'sync',
+ 'status': 'Success',
+ 'status_code': 200,
+ 'metadata': None
+ },
+ 'method': 'DELETE',
+ 'url': r'^http://pylxd.test/1.0/images/aliases/an-alias$'
+ },
# Networks
{
diff --git a/pylxd/tests/test_image.py b/pylxd/tests/test_image.py
index 756e56f..6822865 100644
--- a/pylxd/tests/test_image.py
+++ b/pylxd/tests/test_image.py
@@ -180,3 +180,123 @@ def error(request, context):
a_image = self.client.images.all()[0]
self.assertRaises(exceptions.LXDAPIException, a_image.export)
+
+ def test_add_alias(self):
+ """Try to add an alias."""
+ def updated_image(request, context):
+ context.status_code = 200
+ return json.dumps({
+ 'type': 'sync',
+ 'metadata': {
+ 'aliases': [
+ {
+ 'name': 'an-alias', # NOQA
+ 'fingerprint': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' # NOQA
+ },
+ {
+ 'name': 'lol',
+ 'fingerprint': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' # NOQA
+ }
+ ],
+ 'architecture': 'x86_64',
+ 'cached': False,
+ 'filename': 'a_image.tar.bz2',
+ 'fingerprint': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
+ 'public': False,
+ 'properties': {},
+ 'size': 1,
+ 'auto_update': False,
+ 'created_at': '1983-06-16T02:42:00Z',
+ 'expires_at': '1983-06-16T02:42:00Z',
+ 'last_used_at': '1983-06-16T02:42:00Z',
+ 'uploaded_at': '1983-06-16T02:42:00Z',
+ }
+ })
+
+ a_image = self.client.images.all()[0]
+ self.add_rule({
+ 'text': updated_image,
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
+ })
+
+ a_image.add_alias('lol', 'Just LOL')
+
+ aliases = [a['name'] for a in a_image.aliases]
+ self.assertTrue('lol' in aliases, "Image didn't get updated.")
+
+ def test_add_alias_duplicate(self):
+ """Adding a alias twice should raise an LXDAPIException."""
+ def error(request, context):
+ context.status_code = 409
+ return json.dumps({
+ 'type': 'error',
+ 'error': 'already exists',
+ 'error_code': 409})
+ self.add_rule({
+ 'text': error,
+ 'method': 'POST',
+ 'url': r'^http://pylxd.test/1.0/images/aliases$', # NOQA
+ })
+
+ a_image = self.client.images.all()[0]
+
+ self.assertRaises(
+ exceptions.LXDAPIException,
+ a_image.add_alias,
+ 'lol', 'Just LOL'
+ )
+
+ def test_remove_alias(self):
+ """Try to remove an-alias."""
+ def updated_image(request, context):
+ context.status_code = 200
+ return json.dumps({
+ 'type': 'sync',
+ 'metadata': {
+ 'aliases': [],
+ 'architecture': 'x86_64',
+ 'cached': False,
+ 'filename': 'a_image.tar.bz2',
+ 'fingerprint': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', # NOQA
+ 'public': False,
+ 'properties': {},
+ 'size': 1,
+ 'auto_update': False,
+ 'created_at': '1983-06-16T02:42:00Z',
+ 'expires_at': '1983-06-16T02:42:00Z',
+ 'last_used_at': '1983-06-16T02:42:00Z',
+ 'uploaded_at': '1983-06-16T02:42:00Z',
+ }
+ })
+
+ a_image = self.client.images.all()[0]
+ self.add_rule({
+ 'text': updated_image,
+ 'method': 'GET',
+ 'url': r'^http://pylxd.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
+ })
+
+ a_image.delete_alias('an-alias')
+ self.assertEqual(0, len(a_image.aliases), "Alias didn't get deleted.")
+
+ def test_remove_alias_error(self):
+ """Try to remove an non existant alias."""
+ def error(request, context):
+ context.status_code = 404
+ return json.dumps({
+ 'type': 'error',
+ 'error': 'not found',
+ 'error_code': 404})
+ self.add_rule({
+ 'text': error,
+ 'method': 'DELETE',
+ 'url': r'^http://pylxd.test/1.0/images/aliases/lol$', # NOQA
+ })
+
+ a_image = self.client.images.all()[0]
+ self.assertRaises(
+ exceptions.LXDAPIException,
+ a_image.delete_alias,
+ 'lol'
+ )
More information about the lxc-devel
mailing list