Add cmd to share openstack images 83/12483/5
authorThanh Ha <thanh.ha@linuxfoundation.org>
Fri, 7 Sep 2018 03:06:18 +0000 (23:06 -0400)
committerThanh Ha <thanh.ha@linuxfoundation.org>
Fri, 7 Sep 2018 19:22:29 +0000 (15:22 -0400)
Allows us to more easily share images to multiple openstack tenants.

Issue: RELENG-1201
Change-Id: I58dc200f7b29429ee1215bacdc533d234ad153fb
Signed-off-by: Thanh Ha <thanh.ha@linuxfoundation.org>
lftools/openstack/cmd.py
lftools/openstack/image.py
releasenotes/notes/share-openstack-images-4f1e3d18fdcb488b.yaml [new file with mode: 0644]

index a0b6c5f..9cafdf3 100644 (file)
@@ -81,8 +81,18 @@ def list(ctx, days, hide_public, ci_managed):
         hide_public=hide_public)
 
 
+@click.command()
+@click.argument('image')
+@click.argument('dest', nargs=-1)
+@click.pass_context
+def share(ctx, image, dest):
+    """Share image with another tenant."""
+    os_image.share(ctx.obj['os_cloud'], image, dest)
+
+
 image.add_command(cleanup)
 image.add_command(list)
+image.add_command(share)
 
 
 @openstack.group()
index 5ca9259..4757a00 100644 (file)
@@ -14,9 +14,14 @@ __author__ = 'Thanh Ha'
 
 from datetime import datetime
 from datetime import timedelta
+import logging
+import subprocess
+import sys
 
 import shade
 
+log = logging.getLogger(__name__)
+
 
 def _filter_images(images, days=0, hide_public=False, ci_managed=True):
     """Filter image data and return list.
@@ -100,3 +105,78 @@ def cleanup(os_cloud, days=0, hide_public=False, ci_managed=True, clouds=None):
             _remove_images_from_cloud(filtered_images, c)
     else:
         _remove_images_from_cloud(filtered_images, cloud)
+
+
+def share(os_cloud, image, clouds):
+    """Share image with another tenant."""
+    def _get_image_id(os_cloud, image):
+        cmd = ['openstack', '--os-cloud', os_cloud, 'image', 'list',
+               '--name', image, '-f', 'value', '-c', 'ID']
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        log.debug('exit code: {}'.format(p.returncode))
+        log.debug(stderr.decode('utf-8'))
+        if p.returncode:
+            sys.exit(1)
+
+        image_id = stdout.decode('utf-8').strip()
+        log.debug('image_id: {}'.format(image_id))
+        return image_id
+
+    def _mark_image_shared(os_cloud, image):
+        cmd = ['openstack', '--os-cloud', os_cloud, 'image', 'set', '--shared', image]
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        log.debug('exit code: {}'.format(p.returncode))
+        log.debug(stderr.decode('utf-8'))
+        if p.returncode:
+            sys.exit(1)
+
+    def _get_token(cloud):
+        cmd = ['openstack', '--os-cloud', cloud, 'token', 'issue',
+               '-c', 'project_id', '-f', 'value']
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        log.debug('exit code: {}'.format(p.returncode))
+        log.debug(stderr.decode('utf-8'))
+        if p.returncode:
+            sys.exit(1)
+
+        token = stdout.decode('utf-8').strip()
+        log.debug('token: {}'.format(token))
+        return token
+
+    def _share_to_cloud(os_cloud, image, token):
+        log.debug('Sharing image {} to {}'.format(image, token))
+        cmd = ['openstack', '--os-cloud', os_cloud, 'image', 'add', 'project',
+               image, token]
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        log.debug('exit code: {}'.format(p.returncode))
+        log.debug(stderr.decode('utf-8'))
+
+        if p.returncode:
+            if stderr.decode('utf-8').startswith('409 Conflict'):
+                log.info('  Image is already shared.')
+            else:
+                sys.exit(1)
+
+    def _accept_shared_image(cloud, image):
+        log.debug('Accepting image {}'.format(image))
+        cmd = ['openstack', '--os-cloud', cloud, 'image', 'set',
+               '--accept', image]
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        log.debug('exit code: {}'.format(p.returncode))
+        log.debug(stderr.decode('utf-8'))
+        if p.returncode:
+            sys.exit(1)
+
+    log.info('Marking {}\'s image "{}" as shared.'.format(os_cloud, image))
+    image_id = _get_image_id(os_cloud, image)
+    _mark_image_shared(os_cloud, image_id)
+
+    for cloud in clouds:
+        log.info('Sharing to {}.'.format(cloud))
+        _share_to_cloud(os_cloud, image_id, _get_token(cloud))
+        _accept_shared_image(cloud, image_id)
diff --git a/releasenotes/notes/share-openstack-images-4f1e3d18fdcb488b.yaml b/releasenotes/notes/share-openstack-images-4f1e3d18fdcb488b.yaml
new file mode 100644 (file)
index 0000000..7a72b2a
--- /dev/null
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Add an ``openstack image share`` sub-command to handle sharing images
+    between multiple tenants. Command accepts a space-separated list of tenants
+    to share the provided image with.
+
+    Usage: ``lftools openstack image share [OPTIONS] IMAGE [DEST]...``