Name generator util function

This adds a name generator function for cluster nodes. When provided
with a fmt that has "$nR" or "$nI" in it, the util function will perform
in-place substitution of the format string. The "$R" will be replaced
with a random string, the "$I" will be replaced with the node index.
The "n" in the format string is optional. When specified, it creates the
random string of given length, or a string representation of node index
left padded with 0s.

Change-Id: I6dfd95be4a315917bbc4920678921618df4792c0
This commit is contained in:
tengqm 2017-12-13 02:01:01 -05:00
parent d4a9cb8287
commit 0f3a407208
2 changed files with 78 additions and 0 deletions

View File

@ -15,6 +15,7 @@ Common utilities module.
"""
import random
import re
import string
from jsonpath_rw import parse
@ -142,6 +143,50 @@ def random_name(length=8):
return lead + tail
def format_node_name(fmt, cluster, index):
"""Generates a node name using the given format.
:param fmt: A string containing format directives. Currently we only
support the following keys:
- "$nR": a random string with at most 'n' characters where
'n' defaults to 8.
- "$nI": a string representation of the node index where 'n'
instructs the number of digits generated with 0s
padded to the left.
:param cluster: The DB object for the cluster to which the node belongs.
This parameter is provided for future extension.
:param index: The index for the node in the target cluster.
:returns: A string containing the generated node name.
"""
# for backward compatibility
if not fmt:
fmt = "node-$8R"
result = ""
last = 0
pattern = re.compile("(\$\d{0,8}[RI])")
for m in pattern.finditer(fmt):
group = m.group()
t = group[-1]
width = group[1:-1]
if t == "R": # random string
if width != "":
sub = random_name(int(width))
else:
sub = random_name(8)
elif t == "I": # node index
if width != "":
str_index = str(index)
sub = str_index.zfill(int(width))
else:
sub = str(index)
result += fmt[last:m.start()] + sub
last = m.end()
result += fmt[last:]
return result
def isotime(at):
"""Stringify time in ISO 8601 format.

View File

@ -155,6 +155,39 @@ class TestRandomName(base.SenlinTestCase):
self.assertEqual('', result)
class TestFormatNodeName(base.SenlinTestCase):
def test_empty(self):
res = utils.format_node_name(None, None, 0)
self.assertIsNotNone(res)
self.assertEqual(13, len(res))
res = utils.format_node_name("", None, 0)
self.assertIsNotNone(res)
self.assertEqual(13, len(res))
def test_has_random(self):
res = utils.format_node_name("prefix-$R", None, 0)
self.assertEqual(15, len(res))
res = utils.format_node_name("prefix-$5R", None, 0)
self.assertEqual(12, len(res))
def test_has_index(self):
res = utils.format_node_name("prefix-$I", None, 12)
self.assertEqual(9, len(res))
res = utils.format_node_name("prefix-$5I", None, 12)
self.assertEqual(12, len(res))
def test_has_both(self):
res = utils.format_node_name("prefix-$3R-$I", None, 12)
self.assertEqual(13, len(res))
res = utils.format_node_name("$3R-prefix-$5I", None, 12)
self.assertEqual(16, len(res))
class TestParseLevelValues(base.SenlinTestCase):
def test_none(self):