Alphabetic inventory hostname patterns.

- Code, docs, tests.
  - Also added test of large range 000-142 to verify alpha range did not
    break this.
This commit is contained in:
Norman J. Harman Jr 2012-12-10 20:48:38 -06:00
parent 959a461080
commit 6603737e4d
5 changed files with 54 additions and 37 deletions

View file

@ -48,8 +48,9 @@ Adding a lot of hosts? In 0.6 and later, if you have a lot of hosts following s
[webservers]
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
+++++++++++++++++
@ -57,7 +58,7 @@ Selecting Targets
We'll go over how to use the command line in :doc:`examples` section, however, basically it looks like this::
ansible <pattern_goes_here> -m <module_name> -a <arguments>
Such as::
ansible webservers -m service -a "name=httpd state=restarted"
@ -70,7 +71,7 @@ This is done by designating particular host names or groups of hosts.
The following patterns target all hosts in the inventory file::
all
*
*
Basically 'all' is an alias for '*'. It is also possible to address a specific host or hosts::
@ -78,7 +79,7 @@ Basically 'all' is an alias for '*'. It is also possible to address a specific
one.example.com:two.example.com
192.168.1.50
192.168.1.*
The following patterns address one or more groups, which are denoted
with the aforementioned bracket headers in the inventory file::
@ -105,7 +106,7 @@ Host Variables
++++++++++++++
It is easy to assign variables to hosts that will be used later in playbooks::
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
@ -188,7 +189,7 @@ the 'raleigh' group might look like::
It is ok if these files do not exist, this is an optional feature.
Tip: Keeping your inventory file and variables in a git repo (or other version control)
Tip: Keeping your inventory file and variables in a git repo (or other version control)
is an excellent way to track changes to your inventory and host variables.
.. versionadded:: 0.5

View file

@ -20,8 +20,8 @@
'''
This module is for enhancing ansible's inventory parsing capability such
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
defaults to 0.
form of [beg:end], example: [1:5], [a:c], [D:G]. If beg is not specified,
it defaults to 0.
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
@ -30,6 +30,7 @@ expanded into 001, 002 ...009, 010.
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.
'''
import string
from ansible import errors
@ -81,17 +82,23 @@ def expand_hostname_range(line = None):
raise errors.AnsibleError("host range end value missing")
if beg[0] == '0' and len(beg) > 1:
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:
rlen = None
if rlen > 1 and rlen != len(end):
raise errors.AnsibleError("host range format incorrectly specified!")
fill = str
for _ in range(int(beg), int(end)+1):
if rlen:
rseq = str(_).zfill(rlen) # range sequence
else:
rseq = str(_)
hname = ''.join((head, rseq, tail))
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!")
seq = string.ascii_letters[i_beg:i_end+1]
except ValueError: # not a alpha range
seq = range(int(beg), int(end)+1)
for rseq in seq:
hname = ''.join((head, fill(rseq), tail))
all_hosts.append(hname)
return all_hosts

View file

@ -9,9 +9,10 @@ class TestInventory(unittest.TestCase):
self.cwd = os.getcwd()
self.test_dir = os.path.join(self.cwd, 'test')
self.inventory_file = os.path.join(self.test_dir, 'simple_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_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.inventory_script = os.path.join(self.test_dir, 'inventory_api.py')
os.chmod(self.inventory_script, 0755)
@ -29,38 +30,36 @@ class TestInventory(unittest.TestCase):
def simple_inventory(self):
return Inventory(self.inventory_file)
def large_range_inventory(self):
return Inventory(self.large_range_inventory_file)
def script_inventory(self):
return Inventory(self.inventory_script)
def complex_inventory(self):
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
def test_simple(self):
inventory = self.simple_inventory()
hosts = inventory.list_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)
self.assertEqual(sorted(hosts), sorted(self.all_simple_hosts))
def test_simple_all(self):
inventory = self.simple_inventory()
hosts = inventory.list_hosts('all')
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)
self.assertEqual(sorted(hosts), sorted(self.all_simple_hosts))
def test_simple_norse(self):
inventory = self.simple_inventory()
@ -132,6 +131,11 @@ class TestInventory(unittest.TestCase):
print 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
@ -252,7 +256,7 @@ class TestInventory(unittest.TestCase):
vars = inventory.get_variables('zeus')
print "VARS=%s" % vars
assert vars == {'inventory_hostname': 'zeus',
'inventory_hostname_short': 'zeus',
'group_names': ['greek', 'major-god']}

1
test/large_range Normal file
View file

@ -0,0 +1 @@
bob[000:142]

View file

@ -13,3 +13,7 @@ cottus[99:100]
thor
odin
loki
[egyptian]
Hotep-[a:c]
Bast[C:D]