Add support for volume management 54/10054/3
authorThanh Ha <thanh.ha@linuxfoundation.org>
Tue, 17 Apr 2018 15:39:20 +0000 (11:39 -0400)
committerThanh Ha <thanh.ha@linuxfoundation.org>
Tue, 17 Apr 2018 16:54:33 +0000 (12:54 -0400)
Issue: RELENG-853
Change-Id: Id412315238abfdea9f655dfeb2957964b37d5f19
Signed-off-by: Thanh Ha <thanh.ha@linuxfoundation.org>
.coafile
lftools/openstack/cmd.py
lftools/openstack/volume.py [new file with mode: 0644]

index ba5f8c3..b18c129 100644 (file)
--- a/.coafile
+++ b/.coafile
@@ -30,7 +30,7 @@ bears = BanditBear,
     PyDocStyleBear,
     PyFlakesBear,
     PyImportSortBear
-files = **.py
+files = lftools/**.py
 ignore += docs/conf.py
 known_first_party_imports = lftools
 known_third_party_imports = pytest, six
index 5dfdf61..0a110de 100644 (file)
@@ -17,6 +17,7 @@ import click
 
 from lftools.openstack import image as os_image
 from lftools.openstack import server as os_server
+from lftools.openstack import volume as os_volume
 
 
 @click.group()
@@ -131,3 +132,53 @@ def remove(ctx, server, minutes):
 server.add_command(cleanup)
 server.add_command(list)
 server.add_command(remove)
+
+
+@openstack.group()
+@click.pass_context
+def volume(ctx):
+    """Command for manipulating volumes."""
+    pass
+
+
+@click.command()
+@click.option(
+    '--days', type=int, default=0,
+    help='Find volumes older than or equal to days.')
+@click.pass_context
+def cleanup(ctx, days):
+    """Cleanup old volumes."""
+    os_volume.cleanup(
+        ctx.obj['os_cloud'],
+        days=days)
+
+
+@click.command()
+@click.option(
+    '--days', type=int, default=0,
+    help='Find volumes older than or equal to days.')
+@click.pass_context
+def list(ctx, days):
+    """List cloud volumes."""
+    os_volume.list(
+        ctx.obj['os_cloud'],
+        days=days)
+
+
+@click.command()
+@click.argument('volume')
+@click.option(
+    '--minutes', type=int, default=0,
+    help='Delete volumes if older than x minutes.')
+@click.pass_context
+def remove(ctx, volume, minutes):
+    """Remove volumes."""
+    os_volume.remove(
+        ctx.obj['os_cloud'],
+        volume_name=volume,
+        minutes=minutes)
+
+
+volume.add_command(cleanup)
+volume.add_command(list)
+volume.add_command(remove)
diff --git a/lftools/openstack/volume.py b/lftools/openstack/volume.py
new file mode 100644 (file)
index 0000000..3e0367c
--- /dev/null
@@ -0,0 +1,94 @@
+# -*- code: utf-8 -*-
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2018 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+"""volume related sub-commands for openstack command."""
+
+__author__ = 'Thanh Ha'
+
+from datetime import datetime
+from datetime import timedelta
+import sys
+
+import shade
+
+
+def _filter_volumes(volumes, days=0):
+    """Filter volume data and return list."""
+    filtered = []
+    for volume in volumes:
+        if days and (
+                datetime.strptime(volume.created_at, '%Y-%m-%dT%H:%M:%S.%f')
+                >= datetime.now() - timedelta(days=days)):
+            continue
+
+        filtered.append(volume)
+    return filtered
+
+
+def list(os_cloud, days=0):
+    """List volumes found according to parameters."""
+    cloud = shade.openstack_cloud(cloud=os_cloud)
+    volumes = cloud.list_volumes()
+
+    filtered_volumes = _filter_volumes(volumes, days)
+    for volume in filtered_volumes:
+        print(volume.name)
+
+
+def cleanup(os_cloud, days=0):
+    """Remove volume from cloud.
+
+    :arg str os_cloud: Cloud name as defined in OpenStack clouds.yaml.
+    :arg int days: Filter volumes that are older than number of days.
+    """
+    def _remove_volumes_from_cloud(volumes, cloud):
+        print('Removing {} volumes from {}.'.format(len(volumes), cloud.cloud_config.name))
+        for volume in volumes:
+            try:
+                result = cloud.delete_volume(volume.name)
+            except shade.exc.OpenStackCloudException as e:
+                if str(e).startswith('Multiple matches found for'):
+                    print('WARNING: {}. Skipping volume...'.format(str(e)))
+                    continue
+                else:
+                    print('ERROR: Unexpected exception: {}'.format(str(e)))
+                    raise
+
+            if not result:
+                print('WARNING: Failed to remove \"{}\" from {}. Possibly already deleted.'
+                      .format(volume.name, cloud.cloud_config.name))
+            else:
+                print('Removed "{}" from {}.'.format(volume.name, cloud.cloud_config.name))
+
+    cloud = shade.openstack_cloud(cloud=os_cloud)
+    volumes = cloud.list_volumes()
+    filtered_volumes = _filter_volumes(volumes, days)
+    _remove_volumes_from_cloud(filtered_volumes, cloud)
+
+
+def remove(os_cloud, volume_name, minutes=0):
+    """Remove a volume from cloud.
+
+    :arg str os_cloud: Cloud name as defined in OpenStack clouds.yaml.
+    :arg int minutes: Only delete volume if it is older than number of minutes.
+    """
+    cloud = shade.openstack_cloud(cloud=os_cloud)
+    volume = cloud.get_volume(volume_name)
+
+    if not volume:
+        print("ERROR: volume not found.")
+        sys.exit(1)
+
+    if (datetime.strptime(volume.created, '%Y-%m-%dT%H:%M:%SZ')
+            >= datetime.utcnow() - timedelta(minutes=minutes)):
+        print('WARN: volume "{}" is not older than {} minutes.'.format(
+            volume.name, minutes))
+    else:
+        cloud.delete_volume(volume.name)