From 7ef0786d9e6172a9df0d33a1113f27569bd7f522 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Mon, 23 Jul 2012 22:05:22 +0000 Subject: Fix image-create --poll race-condition. This fixes a race-condition caused by `do_image_create` with polling enabled returning after the image has finished uploading but before the instance `task_state` was cleared out. This would cause a snapshot taken immediately afterwards to fail because the `task_state` would still be in the `image_snapshot` state. The (short-term) fix is to add an addition poll-loop that ensures the `task_state` field is cleared-out as well. Change-Id: I3adeed24ecea127c8bdd12143634a6ce5da64330 --- novaclient/v1_1/shell.py | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py index 4200f5f2..3b358ca2 100644 --- a/novaclient/v1_1/shell.py +++ b/novaclient/v1_1/shell.py @@ -248,7 +248,8 @@ def do_cloudpipe_create(cs, args): def _poll_for_status(poll_fn, obj_id, action, final_ok_states, - poll_period=5, show_progress=True): + poll_period=5, show_progress=True, + status_field="status", silent=False): """Block while an action is being performed, periodically printing progress. """ @@ -262,21 +263,32 @@ def _poll_for_status(poll_fn, obj_id, action, final_ok_states, sys.stdout.write(msg) sys.stdout.flush() - print + if not silent: + print + while True: obj = poll_fn(obj_id) - status = obj.status.lower() + + status = getattr(obj, status_field) + + if status: + status = status.lower() + progress = getattr(obj, 'progress', None) or 0 if status in final_ok_states: - print_progress(100) - print "\nFinished" + if not silent: + print_progress(100) + print "\nFinished" break elif status == "error": - print "\nError %(action)s instance" % locals() + if not silent: + print "\nError %(action)s instance" % locals() break - else: + + if not silent: print_progress(progress) - time.sleep(poll_period) + + time.sleep(poll_period) def _translate_flavor_keys(collection): @@ -753,6 +765,21 @@ def do_image_create(cs, args): _poll_for_status(cs.images.get, image_uuid, 'snapshotting', ['active']) + # NOTE(sirp): A race-condition exists between when the image finishes + # uploading and when the servers's `task_state` is cleared. To account + # for this, we need to poll a second time to ensure the `task_state` is + # cleared before returning, ensuring that a snapshot taken immediately + # after this function returns will succeed. + # + # A better long-term solution will be to separate 'snapshotting' and + # 'image-uploading' in Nova and clear the task-state once the VM + # snapshot is complete but before the upload begins. + task_state_field = "OS-EXT-STS:task_state" + if hasattr(server, task_state_field): + _poll_for_status(cs.servers.get, server.id, 'image_snapshot', + [None], status_field=task_state_field, + show_progress=False, silent=True) + @utils.arg('server', metavar='', -- cgit v1.2.1