Commit 04195e20 by Michael DeHaan

Merge pull request #1747 from njharman/alpharange

Alphabetic inventory hostname patterns.
parents 4bcdd246 6603737e
...@@ -48,8 +48,9 @@ Adding a lot of hosts? In 0.6 and later, if you have a lot of hosts following s ...@@ -48,8 +48,9 @@ Adding a lot of hosts? In 0.6 and later, if you have a lot of hosts following s
[webservers] [webservers]
www[01:50].example.com www[01:50].example.com
db-[a:f].example.com
Leading zeros can be included or removed, as desired, and the ranges are inclusive. For numeric patterns, leading zeros can be included or removed, as desired. Ranges are inclusive.
Selecting Targets Selecting Targets
+++++++++++++++++ +++++++++++++++++
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
''' '''
This module is for enhancing ansible's inventory parsing capability such This module is for enhancing ansible's inventory parsing capability such
that it can deal with hostnames specified using a simple pattern in the that it can deal with hostnames specified using a simple pattern in the
form of [beg:end], example: [1:5] where if beg is not specified, it form of [beg:end], example: [1:5], [a:c], [D:G]. If beg is not specified,
defaults to 0. it defaults to 0.
If beg is given and is left-zero-padded, e.g. '001', it is taken as a If beg is given and is left-zero-padded, e.g. '001', it is taken as a
formatting hint when the range is expanded. e.g. [001:010] is to be formatting hint when the range is expanded. e.g. [001:010] is to be
...@@ -30,6 +30,7 @@ expanded into 001, 002 ...009, 010. ...@@ -30,6 +30,7 @@ expanded into 001, 002 ...009, 010.
Note that when beg is specified with left zero padding, then the length of Note that when beg is specified with left zero padding, then the length of
end must be the same as that of beg, else a exception is raised. end must be the same as that of beg, else a exception is raised.
''' '''
import string
from ansible import errors from ansible import errors
...@@ -81,17 +82,23 @@ def expand_hostname_range(line = None): ...@@ -81,17 +82,23 @@ def expand_hostname_range(line = None):
raise errors.AnsibleError("host range end value missing") raise errors.AnsibleError("host range end value missing")
if beg[0] == '0' and len(beg) > 1: if beg[0] == '0' and len(beg) > 1:
rlen = len(beg) # range length formatting hint rlen = len(beg) # range length formatting hint
if rlen != len(end):
raise errors.AnsibleError("host range format incorrectly specified!")
fill = lambda _: str(_).zfill(rlen) # range sequence
else: else:
rlen = None fill = str
if rlen > 1 and rlen != len(end):
try:
i_beg = string.ascii_letters.index(beg)
i_end = string.ascii_letters.index(end)
if i_beg > i_end:
raise errors.AnsibleError("host range format incorrectly specified!") raise errors.AnsibleError("host range format incorrectly specified!")
seq = string.ascii_letters[i_beg:i_end+1]
except ValueError: # not a alpha range
seq = range(int(beg), int(end)+1)
for _ in range(int(beg), int(end)+1): for rseq in seq:
if rlen: hname = ''.join((head, fill(rseq), tail))
rseq = str(_).zfill(rlen) # range sequence
else:
rseq = str(_)
hname = ''.join((head, rseq, tail))
all_hosts.append(hname) all_hosts.append(hname)
return all_hosts return all_hosts
...@@ -10,6 +10,7 @@ class TestInventory(unittest.TestCase): ...@@ -10,6 +10,7 @@ class TestInventory(unittest.TestCase):
self.test_dir = os.path.join(self.cwd, 'test') self.test_dir = os.path.join(self.cwd, 'test')
self.inventory_file = os.path.join(self.test_dir, 'simple_hosts') self.inventory_file = os.path.join(self.test_dir, 'simple_hosts')
self.large_range_inventory_file = os.path.join(self.test_dir, 'large_range')
self.complex_inventory_file = os.path.join(self.test_dir, 'complex_hosts') self.complex_inventory_file = os.path.join(self.test_dir, 'complex_hosts')
self.inventory_script = os.path.join(self.test_dir, 'inventory_api.py') self.inventory_script = os.path.join(self.test_dir, 'inventory_api.py')
...@@ -29,38 +30,36 @@ class TestInventory(unittest.TestCase): ...@@ -29,38 +30,36 @@ class TestInventory(unittest.TestCase):
def simple_inventory(self): def simple_inventory(self):
return Inventory(self.inventory_file) return Inventory(self.inventory_file)
def large_range_inventory(self):
return Inventory(self.large_range_inventory_file)
def script_inventory(self): def script_inventory(self):
return Inventory(self.inventory_script) return Inventory(self.inventory_script)
def complex_inventory(self): def complex_inventory(self):
return Inventory(self.complex_inventory_file) return Inventory(self.complex_inventory_file)
all_simple_hosts=['jupiter', 'saturn', 'zeus', 'hera',
'cerberus001','cerberus002','cerberus003',
'cottus99', 'cottus100',
'poseidon', 'thor', 'odin', 'loki',
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5',
'Hotep-a', 'Hotep-b', 'Hotep-c',
'BastC', 'BastD', ]
##################################### #####################################
### Simple inventory format tests ### Simple inventory format tests
def test_simple(self): def test_simple(self):
inventory = self.simple_inventory() inventory = self.simple_inventory()
hosts = inventory.list_hosts() hosts = inventory.list_hosts()
self.assertEqual(sorted(hosts), sorted(self.all_simple_hosts))
expected_hosts=['jupiter', 'saturn', 'zeus', 'hera',
'cerberus001','cerberus002','cerberus003',
'cottus99', 'cottus100',
'poseidon', 'thor', 'odin', 'loki',
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5']
assert sorted(hosts) == sorted(expected_hosts)
def test_simple_all(self): def test_simple_all(self):
inventory = self.simple_inventory() inventory = self.simple_inventory()
hosts = inventory.list_hosts('all') hosts = inventory.list_hosts('all')
self.assertEqual(sorted(hosts), sorted(self.all_simple_hosts))
expected_hosts=['jupiter', 'saturn', 'zeus', 'hera',
'cerberus001','cerberus002','cerberus003',
'cottus99', 'cottus100',
'poseidon', 'thor', 'odin', 'loki',
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5']
assert sorted(hosts) == sorted(expected_hosts)
def test_simple_norse(self): def test_simple_norse(self):
inventory = self.simple_inventory() inventory = self.simple_inventory()
...@@ -132,6 +131,11 @@ class TestInventory(unittest.TestCase): ...@@ -132,6 +131,11 @@ class TestInventory(unittest.TestCase):
print expected print expected
assert vars == expected assert vars == expected
def test_large_range(self):
inventory = self.large_range_inventory()
hosts = inventory.list_hosts()
self.assertEqual(sorted(hosts), sorted('bob%03i' %i for i in range(0, 143)))
################################################### ###################################################
### INI file advanced tests ### INI file advanced tests
......
bob[000:142]
...@@ -13,3 +13,7 @@ cottus[99:100] ...@@ -13,3 +13,7 @@ cottus[99:100]
thor thor
odin odin
loki loki
[egyptian]
Hotep-[a:c]
Bast[C:D]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment