
This patch moves the function 'get_next_clone_name' from Wok to Kimchi. The function adds, originally, an incremental number in each clone name, however this approach causes a race condiction if Kimchi tries to clone guest multiple times, sending multiple request at once. If clone requests are done so fast, it is possible that the plugin does not send all resource names in all_names parameter, then the function is going to select the same name for 2 or more clones, which is going to cause errors. To avoid this problem, it is better to use timestamps in the clones names instead of incremental numbers. Then it guarantees names will be unique. Supporting timestamps in microsecond precision, avoids this type of error. New clone name will be "basename-clone-timestamp-name-suffix". Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- utils.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/utils.py b/utils.py index 61b0a7f..eae16d5 100644 --- a/utils.py +++ b/utils.py @@ -23,6 +23,7 @@ import json import os import re import sqlite3 +import time import urllib2 from httplib import HTTPConnection, HTTPException from urlparse import urlparse @@ -208,3 +209,52 @@ def upgrade_objectstore_memory(): if total > 0: wok_log.info( "%d 'template' memory entries upgraded in objectstore.", total) + + +def get_next_clone_name(all_names, basename, name_suffix='', ts=False): + """Find the next available name for a cloned resource. + + If any resource named "<basename>-clone-<number><name_suffix>" is found + in "all_names", use the maximum "number" + 1; else, use 1. + + Arguments: + all_names -- All existing names for the resource type. This list will + be used to make sure the new name won't conflict with + existing names. + basename -- The name of the original resource. + name_suffix -- The resource name suffix (optional). This parameter + exist so that a resource named "foo.img" gets the name + "foo-clone-1.img" instead of "foo.img-clone-1". If this parameter + is used, the suffix should not be present in "basename". + ts -- use timestamp, instead of incremental numbers + + Return: + A UTF-8 string in the format "<basename>-clone-<number><name_suffix>". + """ + re_group_num = 'num' + + # Use timestamps or increase clone number + if ts: + # Microsecond precision + ts_suffix = int(time.time() * 1000000) + new_name = u'%s-clone-%d' % (basename, ts_suffix) + else: + re_expr = u'%s-clone-(?P<%s>\d+)' % (basename, re_group_num) + if name_suffix != '': + re_expr = u'%s%s' % (re_expr, name_suffix) + + max_num = 0 + re_compiled = re.compile(re_expr) + + for n in all_names: + match = re_compiled.match(n) + if match is not None: + max_num = max(max_num, int(match.group(re_group_num))) + + # increments the maximum "clone number" found + new_name = u'%s-clone-%d' % (basename, max_num + 1) + + if name_suffix != '': + new_name = new_name + name_suffix + + return new_name -- 2.1.0