diff --git a/client-api/api_lib/pvcapi.py b/client-api/api_lib/pvcapi.py index a3ac1672..9a8d91be 100755 --- a/client-api/api_lib/pvcapi.py +++ b/client-api/api_lib/pvcapi.py @@ -892,6 +892,23 @@ def ceph_volume_snapshot_add(pool, volume, name): } return flask.jsonify(output), retcode +def ceph_volume_snapshot_rename(pool, volume, name, new_name): + """ + Rename a Ceph RBD volume snapshot in the PVC Ceph storage cluster. + """ + zk_conn = pvc_common.startZKConnection(config['coordinators']) + retflag, retdata = pvc_ceph.rename_snapshot(zk_conn, pool, volume, name, new_name) + if retflag: + retcode = 200 + else: + retcode = 400 + + pvc_common.stopZKConnection(zk_conn) + output = { + 'message': retdata.replace('\"', '\'') + } + return flask.jsonify(output), retcode + def ceph_volume_snapshot_remove(pool, volume, name): """ Remove a Ceph RBD volume snapshot from the PVC Ceph storage cluster. diff --git a/client-api/pvc-api.py b/client-api/pvc-api.py index 15ab66d4..720d2db3 100755 --- a/client-api/pvc-api.py +++ b/client-api/pvc-api.py @@ -870,8 +870,12 @@ def api_ceph_volume_snapshot_element(pool, volume, snapshot): return pvcapi.ceph_volume_snapshot_list(pool, volume, snapshot) if flask.request.method == 'PUT': - # TODO: #44 - flask.abort(501) + if 'name' in flask.request.values: + name = flask.request.values['name'] + else: + return flask.jsonify({"message":"ERROR: A new name must be specified."}), 400 + + return pvcapi.ceph_volume_snapshot_rename(pool, volume, snapshot, name) if flask.request.method == 'DELETE': return pvcapi.ceph_volume_snapshot_remove(pool, volume, snapshot) diff --git a/client-cli/pvc.py b/client-cli/pvc.py index 23bae666..859fc1b5 100755 --- a/client-cli/pvc.py +++ b/client-cli/pvc.py @@ -1573,13 +1573,37 @@ def ceph_volume_snapshot(): ) def ceph_volume_snapshot_add(pool, volume, name): """ - Add a snapshot of Ceph RBD volume VOLUME with name NAME. + Add a snapshot with name NAME of Ceph RBD volume VOLUME in pool POOL. """ zk_conn = pvc_common.startZKConnection(zk_host) retcode, retmsg = pvc_ceph.add_snapshot(zk_conn, pool, volume, name) cleanup(retcode, retmsg, zk_conn) +############################################################################### +# pvc storage ceph volume snapshot rename +############################################################################### +@click.command(name='rename', short_help='Rename RBD volume snapshot.') +@click.argument( + 'pool' +) +@click.argument( + 'volume' +) +@click.argument( + 'name' +) +@click.argument( + 'new_name' +) +def ceph_volume_snapshot_rename(pool, volume, name, new_name): + """ + Rename an existing Ceph RBD volume snapshot with name NAME to name NEW_NAME for volume VOLUME in pool POOL. + """ + zk_conn = pvc_common.startZKConnection(zk_host) + retcode, retmsg = pvc_ceph.rename_snapshot(zk_conn, pool, volume, name, new_name) + cleanup(retcode, retmsg, zk_conn) + ############################################################################### # pvc storage ceph volume snapshot remove ############################################################################### @@ -1600,7 +1624,7 @@ def ceph_volume_snapshot_add(pool, volume, name): ) def ceph_volume_snapshot_remove(pool, volume, name, yes): """ - Remove a Ceph RBD volume with name NAME from pool POOL. + Remove a Ceph RBD volume snapshot with name NAME from volume VOLUME in pool POOL. """ if not yes: @@ -1802,6 +1826,7 @@ ceph_volume.add_command(ceph_volume_list) ceph_volume.add_command(ceph_volume_snapshot) ceph_volume_snapshot.add_command(ceph_volume_snapshot_add) +ceph_volume_snapshot.add_command(ceph_volume_snapshot_rename) ceph_volume_snapshot.add_command(ceph_volume_snapshot_remove) ceph_volume_snapshot.add_command(ceph_volume_snapshot_list) diff --git a/client-common/ceph.py b/client-common/ceph.py index 4129b221..10aabb2f 100644 --- a/client-common/ceph.py +++ b/client-common/ceph.py @@ -1242,6 +1242,35 @@ def add_snapshot(zk_conn, pool, volume, name): return success, message +def rename_snapshot(zk_conn, pool, volume, name, new_name): + # Tell the cluster to rename + rename_snapshot_string = 'snapshot_rename {},{},{}'.format(pool, name, new_name) + zkhandler.writedata(zk_conn, {'/ceph/cmd': rename_snapshot_string}) + # Wait 1/2 second for the cluster to get the message and start working + time.sleep(0.5) + # Acquire a read lock, so we get the return exclusively + lock = zkhandler.readlock(zk_conn, '/ceph/cmd') + with lock: + try: + result = zkhandler.readdata(zk_conn, '/ceph/cmd').split()[0] + if result == 'success-snapshot_rename': + message = 'Renamed RBD volume snapshot "{}" to "{}" for volume {} on pool "{}".'.format(name, new_name, volume, pool) + success = True + else: + message = 'ERROR: Failed to rename volume {} to {}; check node logs for details.'.format(name, new_name) + success = False + except: + message = 'ERROR: Command ignored by node.' + success = False + + # Acquire a write lock to ensure things go smoothly + lock = zkhandler.writelock(zk_conn, '/ceph/cmd') + with lock: + time.sleep(1) + zkhandler.writedata(zk_conn, {'/ceph/cmd': ''}) + + return success, message + def remove_snapshot(zk_conn, pool, volume, name): if not verifySnapshot(zk_conn, pool, volume, name): return False, 'ERROR: No snapshot with name "{}" is present of volume {} on pool {}.'.format(name, volume, pool)