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(a)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