mirror of
https://github.com/ansible/awx.git
synced 2026-03-11 14:39:30 -02:30
Merge pull request #6120 from AlanCoding/ansible-inventory
Inventory updates through `ansible-inventory`
This commit is contained in:
@@ -9,68 +9,86 @@ import mock
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
# AWX
|
||||
from awx.main.management.commands.inventory_import import (
|
||||
Command
|
||||
)
|
||||
from awx.main.management.commands import inventory_import
|
||||
from awx.main.models import Inventory, Host, Group
|
||||
from awx.main.utils.mem_inventory import dict_to_mem_data
|
||||
|
||||
|
||||
TEST_INVENTORY_INI = '''\
|
||||
# Some comment about blah blah blah...
|
||||
|
||||
[webservers]
|
||||
web1.example.com ansible_ssh_host=w1.example.net
|
||||
web2.example.com
|
||||
web3.example.com:1022
|
||||
|
||||
[webservers:vars] # Comment on a section
|
||||
webvar=blah # Comment on an option
|
||||
|
||||
[dbservers]
|
||||
db1.example.com
|
||||
db2.example.com
|
||||
|
||||
[dbservers:vars]
|
||||
dbvar=ugh
|
||||
|
||||
[servers:children]
|
||||
webservers
|
||||
dbservers
|
||||
|
||||
[servers:vars]
|
||||
varb=B
|
||||
|
||||
[all:vars]
|
||||
vara=A
|
||||
|
||||
[others]
|
||||
10.11.12.13
|
||||
10.12.14.16:8022
|
||||
fe80::1610:9fff:fedd:654b
|
||||
[fe80::1610:9fff:fedd:b654]:1022
|
||||
::1
|
||||
'''
|
||||
TEST_INVENTORY_CONTENT = {
|
||||
"_meta": {
|
||||
"hostvars": {}
|
||||
},
|
||||
"all": {
|
||||
"children": [
|
||||
"others",
|
||||
"servers",
|
||||
"ungrouped"
|
||||
],
|
||||
"vars": {
|
||||
"vara": "A"
|
||||
}
|
||||
},
|
||||
"dbservers": {
|
||||
"hosts": [
|
||||
"db1.example.com",
|
||||
"db2.example.com"
|
||||
],
|
||||
"vars": {
|
||||
"dbvar": "ugh"
|
||||
}
|
||||
},
|
||||
"others": {
|
||||
"hosts": {
|
||||
"10.11.12.13": {},
|
||||
"10.12.14.16": {"ansible_port": 8022},
|
||||
"::1": {},
|
||||
"fe80::1610:9fff:fedd:654b": {},
|
||||
"fe80::1610:9fff:fedd:b654": {"ansible_port": 1022}
|
||||
}
|
||||
},
|
||||
"servers": {
|
||||
"children": [
|
||||
"dbservers",
|
||||
"webservers"
|
||||
],
|
||||
"vars": {
|
||||
"varb": "B"
|
||||
}
|
||||
},
|
||||
"ungrouped": {},
|
||||
"webservers": {
|
||||
"hosts": {
|
||||
"web1.example.com": {
|
||||
"ansible_ssh_host": "w1.example.net"
|
||||
},
|
||||
"web2.example.com": {},
|
||||
"web3.example.com": {
|
||||
"ansible_port": 1022
|
||||
}
|
||||
},
|
||||
"vars": {
|
||||
"webvar": "blah"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def test_dir(tmpdir_factory):
|
||||
return tmpdir_factory.mktemp('inv_files', numbered=False)
|
||||
TEST_MEM_OBJECTS = dict_to_mem_data(TEST_INVENTORY_CONTENT)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def ini_file(test_dir):
|
||||
fn = test_dir.join('test_hosts')
|
||||
fn.write(TEST_INVENTORY_INI)
|
||||
return fn
|
||||
def mock_logging(self):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch.object(Command, 'check_license', mock.MagicMock())
|
||||
@pytest.mark.inventory_import
|
||||
@mock.patch.object(inventory_import.Command, 'check_license', mock.MagicMock())
|
||||
@mock.patch.object(inventory_import.Command, 'set_logging_level', mock_logging)
|
||||
class TestInvalidOptionsFunctional:
|
||||
|
||||
def test_invalid_options_invalid_source(self, inventory):
|
||||
# Give invalid file to the command
|
||||
cmd = Command()
|
||||
cmd = inventory_import.Command()
|
||||
with mock.patch('django.db.transaction.rollback'):
|
||||
with pytest.raises(IOError) as err:
|
||||
cmd.handle_noargs(
|
||||
@@ -78,28 +96,33 @@ class TestInvalidOptionsFunctional:
|
||||
source='/tmp/pytest-of-root/pytest-7/inv_files0-invalid')
|
||||
assert 'Source does not exist' in err.value.message
|
||||
|
||||
def test_invalid_inventory_id(self, ini_file):
|
||||
cmd = Command()
|
||||
def test_invalid_inventory_id(self):
|
||||
cmd = inventory_import.Command()
|
||||
with pytest.raises(CommandError) as err:
|
||||
cmd.handle_noargs(inventory_id=42, source=ini_file.dirname)
|
||||
cmd.handle_noargs(inventory_id=42, source='/notapath/shouldnotmatter')
|
||||
assert 'id = 42' in err.value.message
|
||||
assert 'cannot be found' in err.value.message
|
||||
|
||||
def test_invalid_inventory_name(self, ini_file):
|
||||
cmd = Command()
|
||||
def test_invalid_inventory_name(self):
|
||||
cmd = inventory_import.Command()
|
||||
with pytest.raises(CommandError) as err:
|
||||
cmd.handle_noargs(inventory_name='fooservers', source=ini_file.dirname)
|
||||
cmd.handle_noargs(inventory_name='fooservers', source='/notapath/shouldnotmatter')
|
||||
assert 'name = fooservers' in err.value.message
|
||||
assert 'cannot be found' in err.value.message
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@mock.patch.object(Command, 'check_license', mock.MagicMock())
|
||||
@pytest.mark.inventory_import
|
||||
@mock.patch.object(inventory_import.Command, 'check_license', mock.MagicMock())
|
||||
@mock.patch.object(inventory_import.Command, 'set_logging_level', mock_logging)
|
||||
class TestINIImports:
|
||||
|
||||
def test_inventory_single_ini_import(self, inventory, ini_file, capsys):
|
||||
cmd = Command()
|
||||
r = cmd.handle_noargs(inventory_id=inventory.pk, source=ini_file.dirname)
|
||||
@mock.patch.object(inventory_import.AnsibleInventoryLoader, 'load', mock.MagicMock(return_value=TEST_MEM_OBJECTS))
|
||||
def test_inventory_single_ini_import(self, inventory, capsys):
|
||||
cmd = inventory_import.Command()
|
||||
r = cmd.handle_noargs(
|
||||
inventory_id=inventory.pk, source=__file__,
|
||||
method='backport')
|
||||
out, err = capsys.readouterr()
|
||||
assert r is None
|
||||
assert out == ''
|
||||
@@ -117,10 +140,12 @@ class TestINIImports:
|
||||
reloaded_inv = Inventory.objects.get(pk=inventory.pk)
|
||||
assert reloaded_inv.variables_dict == {'vara': 'A'}
|
||||
|
||||
# Groups vars are applied to host in the newer versions
|
||||
assert Host.objects.get(name='web1.example.com').variables_dict == {'ansible_ssh_host': 'w1.example.net'}
|
||||
assert Host.objects.get(name='web3.example.com').variables_dict == {'ansible_ssh_port': 1022}
|
||||
assert Host.objects.get(name='fe80::1610:9fff:fedd:b654').variables_dict == {'ansible_ssh_port': 1022}
|
||||
assert Host.objects.get(name='10.12.14.16').variables_dict == {'ansible_ssh_port': 8022}
|
||||
# Old version uses `ansible_ssh_port` but new version uses `ansible_port`
|
||||
assert Host.objects.get(name='web3.example.com').variables_dict == {'ansible_port': 1022}
|
||||
assert Host.objects.get(name='fe80::1610:9fff:fedd:b654').variables_dict == {'ansible_port': 1022}
|
||||
assert Host.objects.get(name='10.12.14.16').variables_dict == {'ansible_port': 8022}
|
||||
|
||||
servers = Group.objects.get(name='servers')
|
||||
assert servers.variables_dict == {'varb': 'B'}
|
||||
@@ -143,24 +168,53 @@ class TestINIImports:
|
||||
assert invsrc.inventory_updates.count() == 1
|
||||
assert invsrc.inventory_updates.first().status == 'successful'
|
||||
|
||||
def test_inventory_import_group_vars_file(self, inventory, ini_file, tmpdir_factory):
|
||||
# Create an extra group_vars file for group webservers
|
||||
gvarf = tmpdir_factory.mktemp('inv_files/group_vars', numbered=False).join('webservers')
|
||||
gvarf.write('''webservers_only_variable: foobar\n''')
|
||||
# Check creation of ad-hoc inventory source - this was not called with one specified
|
||||
assert reloaded_inv.inventory_sources.count() == 1
|
||||
assert reloaded_inv.inventory_sources.all()[0].source == 'file'
|
||||
|
||||
cmd = Command()
|
||||
cmd.handle_noargs(inventory_id=inventory.pk, source=ini_file.dirname)
|
||||
@mock.patch.object(
|
||||
inventory_import, 'load_inventory_source', mock.MagicMock(
|
||||
return_value=dict_to_mem_data(
|
||||
{
|
||||
"_meta": {
|
||||
"hostvars": {"foo": {"some_hostvar": "foobar"}}
|
||||
},
|
||||
"all": {
|
||||
"children": ["ungrouped"]
|
||||
},
|
||||
"ungrouped": {
|
||||
"hosts": ["foo"]
|
||||
}
|
||||
}).all_group
|
||||
)
|
||||
)
|
||||
def test_hostvars_are_saved(self, inventory):
|
||||
cmd = inventory_import.Command()
|
||||
cmd.handle_noargs(inventory_id=inventory.pk, source='doesnt matter')
|
||||
assert inventory.hosts.count() == 1
|
||||
h = inventory.hosts.all()[0]
|
||||
assert h.name == 'foo'
|
||||
assert h.variables_dict == {"some_hostvar": "foobar"}
|
||||
|
||||
servers = Group.objects.get(name='webservers')
|
||||
assert servers.variables_dict == {'webvar': 'blah', 'webservers_only_variable': 'foobar'}
|
||||
|
||||
def test_inventory_import_host_vars_file(self, inventory, ini_file, tmpdir_factory):
|
||||
# Create an extra host_vars file for one specific host
|
||||
gvarf = tmpdir_factory.mktemp('inv_files/host_vars', numbered=False).join('web1.example.com')
|
||||
gvarf.write('''host_only_variable: foobar\n''')
|
||||
|
||||
cmd = Command()
|
||||
cmd.handle_noargs(inventory_id=inventory.pk, source=ini_file.dirname)
|
||||
|
||||
Host.objects.get(name='web1.example.com').variables_dict == {
|
||||
'ansible_ssh_host': 'w1.example.net', 'host_only_variable': 'foobar'}
|
||||
@mock.patch.object(
|
||||
inventory_import, 'load_inventory_source', mock.MagicMock(
|
||||
return_value=dict_to_mem_data(
|
||||
{
|
||||
"_meta": {
|
||||
"hostvars": {}
|
||||
},
|
||||
"all": {
|
||||
"children": ["fooland", "barland"]
|
||||
},
|
||||
"fooland": {
|
||||
"children": ["barland"]
|
||||
},
|
||||
"barland": {
|
||||
"children": ["fooland"]
|
||||
}
|
||||
}).all_group
|
||||
)
|
||||
)
|
||||
def test_recursive_group_error(self, inventory):
|
||||
cmd = inventory_import.Command()
|
||||
cmd.handle_noargs(inventory_id=inventory.pk, source='doesnt matter')
|
||||
|
||||
Reference in New Issue
Block a user