From f4a4e17bc83331d9fc7cfdd78cd49c8411386b41 Mon Sep 17 00:00:00 2001 From: Thanh Ha Date: Tue, 17 Apr 2018 11:39:20 -0400 Subject: [PATCH] Add support for volume management Issue: RELENG-853 Change-Id: Id412315238abfdea9f655dfeb2957964b37d5f19 Signed-off-by: Thanh Ha --- .coafile | 2 +- lftools/openstack/cmd.py | 51 ++++++++++++++++++++++++ lftools/openstack/volume.py | 94 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 lftools/openstack/volume.py diff --git a/.coafile b/.coafile index ba5f8c31..b18c129a 100644 --- 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 diff --git a/lftools/openstack/cmd.py b/lftools/openstack/cmd.py index 5dfdf614..0a110dea 100644 --- a/lftools/openstack/cmd.py +++ b/lftools/openstack/cmd.py @@ -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 index 00000000..3e0367c8 --- /dev/null +++ b/lftools/openstack/volume.py @@ -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) -- 2.16.6