Merge "Add service cleanup command"

This commit is contained in:
Zuul 2018-01-16 12:26:57 +00:00 committed by Gerrit Code Review
commit d2cf6e6ddc
6 changed files with 129 additions and 0 deletions

@ -606,6 +606,17 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
}
}
def post_workers_cleanup(self, **kw):
response = {
'cleaning': [{'id': '1', 'cluster_name': 'cluster1',
'host': 'host1', 'binary': 'binary'},
{'id': '3', 'cluster_name': 'cluster1',
'host': 'host3', 'binary': 'binary'}],
'unavailable': [{'id': '2', 'cluster_name': 'cluster2',
'host': 'host2', 'binary': 'binary'}],
}
return 200, {}, response
#
# resource filters
#

@ -1241,3 +1241,23 @@ class ShellTest(utils.TestCase):
'--name foo --description bar --bootable '
'--volume-type baz --availability-zone az '
'--metadata k1=v1 k2=v2')
def test_worker_cleanup_before_3_24(self):
self.assertRaises(SystemExit,
self.run_command,
'work-cleanup fakehost')
def test_worker_cleanup(self):
self.run_command('--os-volume-api-version 3.24 '
'work-cleanup --cluster clustername --host hostname '
'--binary binaryname --is-up false --disabled true '
'--resource-id uuid --resource-type Volume')
expected = {'cluster_name': 'clustername',
'host': 'hostname',
'binary': 'binaryname',
'is_up': 'false',
'disabled': 'true',
'resource_id': 'uuid',
'resource_type': 'Volume'}
self.assert_called('POST', '/workers/cleanup', body=expected)

@ -42,6 +42,7 @@ from cinderclient.v3 import volume_transfers
from cinderclient.v3 import volume_type_access
from cinderclient.v3 import volume_types
from cinderclient.v3 import volumes
from cinderclient.v3 import workers
class Client(object):
@ -91,6 +92,7 @@ class Client(object):
self.transfers = volume_transfers.VolumeTransferManager(self)
self.services = services.ServiceManager(self)
self.clusters = clusters.ClusterManager(self)
self.workers = workers.WorkerManager(self)
self.consistencygroups = consistencygroups.\
ConsistencygroupManager(self)
self.groups = groups.GroupManager(self)

@ -1060,6 +1060,52 @@ def do_cluster_disable(cs, args):
utils.print_dict(cluster.to_dict())
@api_versions.wraps('3.24')
@utils.arg('--cluster', metavar='<cluster-name>', default=None,
help='Cluster name. Default=None.')
@utils.arg('--host', metavar='<hostname>', default=None,
help='Service host name. Default=None.')
@utils.arg('--binary', metavar='<binary>', default=None,
help='Service binary. Default=None.')
@utils.arg('--is-up', metavar='<True|true|False|false>', dest='is_up',
default=None, choices=('True', 'true', 'False', 'false'),
help='Filter by up/down status, if set to true services need to be'
' up, if set to false services need to be down. Default is '
'None, which means up/down status is ignored.')
@utils.arg('--disabled', metavar='<True|true|False|false>', default=None,
choices=('True', 'true', 'False', 'false'),
help='Filter by disabled status. Default=None.')
@utils.arg('--resource-id', metavar='<resource-id>', default=None,
help='UUID of a resource to cleanup. Default=None.')
@utils.arg('--resource-type', metavar='<Volume|Snapshot>', default=None,
choices=('Volume', 'Snapshot'),
help='Type of resource to cleanup.')
def do_work_cleanup(cs, args):
"""Request cleanup of services with optional filtering."""
filters = dict(cluster_name=args.cluster, host=args.host,
binary=args.binary, is_up=args.is_up,
disabled=args.disabled, resource_id=args.resource_id,
resource_type=args.resource_type)
filters = {k: v for k, v in filters.items() if v is not None}
cleaning, unavailable = cs.workers.clean(**filters)
columns = ('ID', 'Cluster Name', 'Host', 'Binary')
if cleaning:
print('Following services will be cleaned:')
utils.print_list(cleaning, columns)
if unavailable:
print('There are no alternative nodes to do cleanup for the following '
'services:')
utils.print_list(unavailable, columns)
if not (cleaning or unavailable):
print('No cleanable services matched cleanup criteria.')
@utils.arg('host',
metavar='<host>',
help='Cinder host on which the existing volume resides; '

@ -0,0 +1,44 @@
# Copyright (c) 2016 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Interface to workers API
"""
from cinderclient.apiclient import base as common_base
from cinderclient import base
class Service(base.Resource):
def __repr__(self):
return "<Service (%s): %s in cluster %s>" % (self.id, self.host,
self.cluster_name or '-')
@classmethod
def list_factory(cls, mngr, elements):
return [cls(mngr, element, loaded=True) for element in elements]
class WorkerManager(base.Manager):
base_url = '/workers'
def clean(self, **filters):
url = self.base_url + '/cleanup'
resp, body = self.api.client.post(url, body=filters)
cleaning = Service.list_factory(self, body['cleaning'])
unavailable = Service.list_factory(self, body['unavailable'])
result = common_base.TupleWithMeta((cleaning, unavailable), resp)
return result

@ -0,0 +1,6 @@
---
features:
- |
New ``work-cleanup`` command to trigger server cleanups by other nodes
within a cluster on Active-Active deployments on microversion 3.24 and
higher.