mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Added a host expansion feature to ansible's inventory parsing
This commit is contained in:
parent
2d1c297fb8
commit
e3b2521f01
7 changed files with 87 additions and 16 deletions
|
@ -3,6 +3,11 @@ Ansible Changes By Release
|
||||||
|
|
||||||
0.6 "Cabo" ------------ pending
|
0.6 "Cabo" ------------ pending
|
||||||
|
|
||||||
|
* inventory file can use a line of the form base[beg:end]tail to define a
|
||||||
|
set of hosts, where [beg:end] defines a numerical range. 'beg' can be a
|
||||||
|
a string padded with zero(s) to the left. If so provided, it acts as
|
||||||
|
a formatting hint during hostname expansion. The hint must be confirmed
|
||||||
|
by having an 'end' that has the same length as 'beg'
|
||||||
* groups variable available as a hash to return the hosts in each group name
|
* groups variable available as a hash to return the hosts in each group name
|
||||||
* fetch module now does not fail a system when requesting file paths (ex: logs) that don't exist
|
* fetch module now does not fail a system when requesting file paths (ex: logs) that don't exist
|
||||||
* apt module now takes an optional install-recommends=yes|no (default yes)
|
* apt module now takes an optional install-recommends=yes|no (default yes)
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -6,7 +6,7 @@
|
||||||
# useful targets:
|
# useful targets:
|
||||||
# make sdist ---------------- produce a tarball
|
# make sdist ---------------- produce a tarball
|
||||||
# make rpm ----------------- produce RPMs
|
# make rpm ----------------- produce RPMs
|
||||||
# make debian --------------- produce a dpkg (FIXME?)
|
# make deb ------------------ produce a DEB
|
||||||
# make docs ----------------- rebuild the manpages (results are checked in)
|
# make docs ----------------- rebuild the manpages (results are checked in)
|
||||||
# make tests ---------------- run the tests
|
# make tests ---------------- run the tests
|
||||||
# make pyflakes, make pep8 -- source code checks
|
# make pyflakes, make pep8 -- source code checks
|
||||||
|
|
|
@ -140,7 +140,19 @@ Connection type to use\&. Possible options are
|
||||||
.RE
|
.RE
|
||||||
.SH "INVENTORY"
|
.SH "INVENTORY"
|
||||||
.sp
|
.sp
|
||||||
Ansible stores the hosts it can potentially operate on in an inventory file\&. The syntax is one host per line\&. Groups headers are allowed and are included on their own line, enclosed in square brackets\&.
|
Ansible stores the hosts it can potentially operate on in an inventory
|
||||||
|
file\&. The syntax is one host per line\&. Optionally, ansible can use a
|
||||||
|
line of the form base[beg:end]tail to define a set of hosts, where
|
||||||
|
[beg:end] defines a numerical range. If 'beg' is left out, it
|
||||||
|
defaults to 0\&. An example: mail[1:6].example.com, where 'head'
|
||||||
|
is 'mail', 'beg' is 1, 'end' is 6, and 'tail' is '.example.com'\&. In
|
||||||
|
addition, 'beg' can be a a string padded with zero(s) to the left. If so
|
||||||
|
provided, it acts as a formatting hint during hostname expansion. The usage
|
||||||
|
must be confirmed by having an 'end' that has the same length as 'beg',
|
||||||
|
else an exception is raised. An example: mail[001:003].example.com is to be
|
||||||
|
expanded to mail001.example.com, mail002.example.com, and
|
||||||
|
mail003.example.com\&. Groups headers are allowed and are included on their
|
||||||
|
own line, enclosed in square brackets\&.
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.sp
|
.sp
|
||||||
/etc/ansible/hosts \(em Default inventory file
|
/etc/ansible/hosts \(em Default inventory file
|
||||||
|
|
|
@ -16,6 +16,8 @@ bikeshed.org
|
||||||
bastion.secure.bikeshed.org
|
bastion.secure.bikeshed.org
|
||||||
192.168.100.1
|
192.168.100.1
|
||||||
192.168.100.10
|
192.168.100.10
|
||||||
|
# An example for host expansion that uses the default 'beg' and an 'end'
|
||||||
|
mail[:5].example.com
|
||||||
|
|
||||||
# Ex 2: A collection of hosts belonging to the 'webservers' group
|
# Ex 2: A collection of hosts belonging to the 'webservers' group
|
||||||
[webservers]
|
[webservers]
|
||||||
|
@ -26,6 +28,9 @@ wheel.colors.com
|
||||||
192.168.1.110
|
192.168.1.110
|
||||||
# Your personal website also runs a webserver:
|
# Your personal website also runs a webserver:
|
||||||
myserver.com
|
myserver.com
|
||||||
|
# An example for host expansion that uses both a 'beg' and an 'end', with
|
||||||
|
# the 'beg' acting as a formatting hint during host name expansion
|
||||||
|
www[001:006].example.com
|
||||||
|
|
||||||
# Ex 3: A collection of database servers in the 'dbservers' group
|
# Ex 3: A collection of database servers in the 'dbservers' group
|
||||||
[dbservers]
|
[dbservers]
|
||||||
|
@ -35,3 +40,6 @@ db02.intranet.mydomain.net
|
||||||
10.25.1.57
|
10.25.1.57
|
||||||
# Perhaps you serve a db off your personal server too:
|
# Perhaps you serve a db off your personal server too:
|
||||||
myserver.com
|
myserver.com
|
||||||
|
# An example for host expansion that uses a regular 'beg' and a regular
|
||||||
|
# 'end'
|
||||||
|
db-[99:101]-node.example.com
|
||||||
|
|
|
@ -24,6 +24,8 @@ import subprocess
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.inventory.group import Group
|
from ansible.inventory.group import Group
|
||||||
|
from ansible.inventory.expand_hosts import detect_range
|
||||||
|
from ansible.inventory.expand_hosts import expand_hostname_range
|
||||||
from ansible import errors
|
from ansible import errors
|
||||||
from ansible import utils
|
from ansible import utils
|
||||||
|
|
||||||
|
@ -80,21 +82,40 @@ class InventoryParser(object):
|
||||||
continue
|
continue
|
||||||
hostname = tokens[0]
|
hostname = tokens[0]
|
||||||
port = C.DEFAULT_REMOTE_PORT
|
port = C.DEFAULT_REMOTE_PORT
|
||||||
if hostname.find(":") != -1:
|
# Two cases to check:
|
||||||
tokens2 = hostname.split(":")
|
# 0. A hostname that contains a range pesudo-code and a port
|
||||||
|
# 1. A hostname that contains just a port
|
||||||
|
if (hostname.find("[") != -1 and
|
||||||
|
hostname.find("]") != -1 and
|
||||||
|
hostname.find(":") != -1 and
|
||||||
|
(hostname.rindex("]") < hostname.rindex(":")) or
|
||||||
|
(hostname.find("]") == -1 and hostname.find(":") != -1)):
|
||||||
|
tokens2 = hostname.rsplit(":", 1)
|
||||||
hostname = tokens2[0]
|
hostname = tokens2[0]
|
||||||
port = tokens2[1]
|
port = tokens2[1]
|
||||||
|
|
||||||
host = None
|
host = None
|
||||||
|
_all_hosts = []
|
||||||
if hostname in self.hosts:
|
if hostname in self.hosts:
|
||||||
host = self.hosts[hostname]
|
host = self.hosts[hostname]
|
||||||
|
_all_hosts.append(host)
|
||||||
|
else:
|
||||||
|
if detect_range(hostname):
|
||||||
|
_hosts = expand_hostname_range(hostname)
|
||||||
|
for _ in _hosts:
|
||||||
|
host = Host(name=_, port=port)
|
||||||
|
self.hosts[_] = host
|
||||||
|
_all_hosts.append(host)
|
||||||
else:
|
else:
|
||||||
host = Host(name=hostname, port=port)
|
host = Host(name=hostname, port=port)
|
||||||
self.hosts[hostname] = host
|
self.hosts[hostname] = host
|
||||||
|
_all_hosts.append(host)
|
||||||
if len(tokens) > 1:
|
if len(tokens) > 1:
|
||||||
for t in tokens[1:]:
|
for t in tokens[1:]:
|
||||||
(k,v) = t.split("=")
|
(k,v) = t.split("=")
|
||||||
host.set_variable(k,v)
|
host.set_variable(k,v)
|
||||||
self.groups[active_group_name].add_host(host)
|
for _ in _all_hosts:
|
||||||
|
self.groups[active_group_name].add_host(_)
|
||||||
|
|
||||||
# [southeast:children]
|
# [southeast:children]
|
||||||
# atlanta
|
# atlanta
|
||||||
|
|
|
@ -44,14 +44,24 @@ class TestInventory(unittest.TestCase):
|
||||||
inventory = self.simple_inventory()
|
inventory = self.simple_inventory()
|
||||||
hosts = inventory.list_hosts()
|
hosts = inventory.list_hosts()
|
||||||
|
|
||||||
expected_hosts=['jupiter', 'saturn', 'zeus', 'hera', 'poseidon', 'thor', 'odin', 'loki']
|
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)
|
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')
|
||||||
|
|
||||||
expected_hosts=['jupiter', 'saturn', 'zeus', 'hera', 'poseidon', 'thor', 'odin', 'loki']
|
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)
|
assert sorted(hosts) == sorted(expected_hosts)
|
||||||
|
|
||||||
def test_simple_norse(self):
|
def test_simple_norse(self):
|
||||||
|
@ -65,21 +75,29 @@ class TestInventory(unittest.TestCase):
|
||||||
inventory = self.simple_inventory()
|
inventory = self.simple_inventory()
|
||||||
hosts = inventory.list_hosts("ungrouped")
|
hosts = inventory.list_hosts("ungrouped")
|
||||||
|
|
||||||
expected_hosts=['jupiter', 'saturn']
|
expected_hosts=['jupiter', 'saturn',
|
||||||
|
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
|
||||||
|
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5']
|
||||||
assert sorted(hosts) == sorted(expected_hosts)
|
assert sorted(hosts) == sorted(expected_hosts)
|
||||||
|
|
||||||
def test_simple_combined(self):
|
def test_simple_combined(self):
|
||||||
inventory = self.simple_inventory()
|
inventory = self.simple_inventory()
|
||||||
hosts = inventory.list_hosts("norse:greek")
|
hosts = inventory.list_hosts("norse:greek")
|
||||||
|
|
||||||
expected_hosts=['zeus', 'hera', 'poseidon', 'thor', 'odin', 'loki']
|
expected_hosts=['zeus', 'hera', 'poseidon',
|
||||||
|
'cerberus001','cerberus002','cerberus003',
|
||||||
|
'cottus99','cottus100',
|
||||||
|
'thor', 'odin', 'loki']
|
||||||
assert sorted(hosts) == sorted(expected_hosts)
|
assert sorted(hosts) == sorted(expected_hosts)
|
||||||
|
|
||||||
def test_simple_restrict(self):
|
def test_simple_restrict(self):
|
||||||
inventory = self.simple_inventory()
|
inventory = self.simple_inventory()
|
||||||
|
|
||||||
restricted_hosts = ['hera', 'poseidon', 'thor']
|
restricted_hosts = ['hera', 'poseidon', 'thor']
|
||||||
expected_hosts=['zeus', 'hera', 'poseidon', 'thor', 'odin', 'loki']
|
expected_hosts=['zeus', 'hera', 'poseidon',
|
||||||
|
'cerberus001','cerberus002','cerberus003',
|
||||||
|
'cottus99', 'cottus100',
|
||||||
|
'thor', 'odin', 'loki']
|
||||||
|
|
||||||
inventory.restrict_to(restricted_hosts)
|
inventory.restrict_to(restricted_hosts)
|
||||||
hosts = inventory.list_hosts("norse:greek")
|
hosts = inventory.list_hosts("norse:greek")
|
||||||
|
@ -99,11 +117,15 @@ class TestInventory(unittest.TestCase):
|
||||||
inventory = self.simple_inventory()
|
inventory = self.simple_inventory()
|
||||||
|
|
||||||
hosts = inventory.list_hosts("all:!greek")
|
hosts = inventory.list_hosts("all:!greek")
|
||||||
expected_hosts=['jupiter', 'saturn', 'thor', 'odin', 'loki']
|
expected_hosts=['jupiter', 'saturn', 'thor', 'odin', 'loki',
|
||||||
|
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
|
||||||
|
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5']
|
||||||
assert sorted(hosts) == sorted(expected_hosts)
|
assert sorted(hosts) == sorted(expected_hosts)
|
||||||
|
|
||||||
hosts = inventory.list_hosts("all:!norse:!greek")
|
hosts = inventory.list_hosts("all:!norse:!greek")
|
||||||
expected_hosts=['jupiter', 'saturn']
|
expected_hosts=['jupiter', 'saturn',
|
||||||
|
'thrudgelmir0', 'thrudgelmir1', 'thrudgelmir2',
|
||||||
|
'thrudgelmir3', 'thrudgelmir4', 'thrudgelmir5']
|
||||||
assert sorted(hosts) == sorted(expected_hosts)
|
assert sorted(hosts) == sorted(expected_hosts)
|
||||||
|
|
||||||
def test_simple_vars(self):
|
def test_simple_vars(self):
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
jupiter
|
jupiter
|
||||||
saturn
|
saturn
|
||||||
|
thrudgelmir[:6]
|
||||||
|
|
||||||
[greek]
|
[greek]
|
||||||
zeus
|
zeus
|
||||||
hera:3000
|
hera:3000
|
||||||
poseidon
|
poseidon
|
||||||
|
cerberus[001:004]
|
||||||
|
cottus[99:101]
|
||||||
|
|
||||||
[norse]
|
[norse]
|
||||||
thor
|
thor
|
||||||
|
|
Loading…
Reference in a new issue