diff --git a/test/units/TestPlayVarsFiles.py b/test/units/TestPlayVarsFiles.py new file mode 100644 index 00000000000..cdfa48fe557 --- /dev/null +++ b/test/units/TestPlayVarsFiles.py @@ -0,0 +1,415 @@ +#!/usr/bin/env python + +import os +import shutil +from tempfile import mkstemp +from tempfile import mkdtemp +from ansible.playbook.play import Play +import ansible + +import unittest +from nose.plugins.skip import SkipTest + + +class FakeCallBacks(object): + def __init__(self): + pass + def on_vars_prompt(self): + pass + def on_import_for_host(self, host, filename): + pass + +class FakeInventory(object): + def __init__(self): + self.hosts = {} + def basedir(self): + return "." + def get_variables(self, host, vault_password=None): + if host in self.hosts: + return self.hosts[host] + else: + return {} + +class FakePlayBook(object): + def __init__(self): + self.extra_vars = {} + self.remote_user = None + self.remote_port = None + self.sudo = None + self.sudo_user = None + self.su = None + self.su_user = None + self.transport = None + self.only_tags = None + self.skip_tags = None + self.VARS_CACHE = {} + self.SETUP_CACHE = {} + self.inventory = FakeInventory() + self.callbacks = FakeCallBacks() + + self.VARS_CACHE['localhost'] = {} + + +class TestMe(unittest.TestCase): + + ######################################## + # BASIC FILE LOADING BEHAVIOR TESTS + ######################################## + + def test_play_constructor(self): + # __init__(self, playbook, ds, basedir, vault_password=None) + playbook = FakePlayBook() + ds = { "hosts": "localhost"} + basedir = "." + play = Play(playbook, ds, basedir) + + def test_vars_file(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # create a play with a vars_file + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": [temp_path]} + basedir = "." + play = Play(playbook, ds, basedir) + os.remove(temp_path) + + # make sure the variable was loaded + assert 'foo' in play.vars, "vars_file was not loaded into play.vars" + assert play.vars['foo'] == 'bar', "foo was not set to bar in play.vars" + + def test_vars_file_nonlist_error(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # create a play with a string for vars_files + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": temp_path} + basedir = "." + error_hit = False + try: + play = Play(playbook, ds, basedir) + except: + error_hit = True + os.remove(temp_path) + + assert error_hit == True, "no error was thrown when vars_files was not a list" + + + def test_multiple_vars_files(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # make a second vars file + fd, temp_path2 = mkstemp() + f = open(temp_path2, "wb") + f.write("baz: bang\n") + f.close() + + + # create a play with two vars_files + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": [temp_path, temp_path2]} + basedir = "." + play = Play(playbook, ds, basedir) + os.remove(temp_path) + os.remove(temp_path2) + + # make sure the variables were loaded + assert 'foo' in play.vars, "vars_file was not loaded into play.vars" + assert play.vars['foo'] == 'bar', "foo was not set to bar in play.vars" + assert 'baz' in play.vars, "vars_file2 was not loaded into play.vars" + assert play.vars['baz'] == 'bang', "baz was not set to bang in play.vars" + + def test_vars_files_first_found(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # get a random file path + fd, temp_path2 = mkstemp() + # make sure this file doesn't exist + os.remove(temp_path2) + + # create a play + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": [[temp_path2, temp_path]]} + basedir = "." + play = Play(playbook, ds, basedir) + os.remove(temp_path) + + # make sure the variable was loaded + assert 'foo' in play.vars, "vars_file was not loaded into play.vars" + assert play.vars['foo'] == 'bar', "foo was not set to bar in play.vars" + + def test_vars_files_multiple_found(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # make a second vars file + fd, temp_path2 = mkstemp() + f = open(temp_path2, "wb") + f.write("baz: bang\n") + f.close() + + # create a play + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": [[temp_path, temp_path2]]} + basedir = "." + play = Play(playbook, ds, basedir) + os.remove(temp_path) + os.remove(temp_path2) + + # make sure the variables were loaded + assert 'foo' in play.vars, "vars_file was not loaded into play.vars" + assert play.vars['foo'] == 'bar', "foo was not set to bar in play.vars" + assert 'baz' not in play.vars, "vars_file2 was loaded after vars_file1 was loaded" + + def test_vars_files_assert_all_found(self): + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # make a second vars file + fd, temp_path2 = mkstemp() + # make sure it doesn't exist + os.remove(temp_path2) + + # create a play + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": [temp_path, temp_path2]} + basedir = "." + + error_hit = False + error_msg = None + + try: + play = Play(playbook, ds, basedir) + except ansible.errors.AnsibleError, e: + error_hit = True + error_msg = e + + os.remove(temp_path) + assert error_hit == True, "no error was thrown for missing vars_file" + + + ######################################## + # VARIABLE PRECEDENCE TESTS + ######################################## + + # On the first run vars_files are loaded into play.vars by host == None + # * only files with vars from host==None will work here + # On the secondary run(s), a host is given and the vars_files are loaded into VARS_CACHE + # * this only occurs if host is not None, filename2 has vars in the name, and filename3 does not + + # filename -- the original string + # filename2 -- filename templated with play vars + # filename3 -- filename2 template with inject (hostvars + setup_cache + vars_cache) + # filename4 -- path_dwim(filename3) + + def test_vars_files_for_host(self): + + # host != None + # vars in filename2 + # no vars in filename3 + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # build play attributes + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": ["{{ temp_path }}"]} + basedir = "." + playbook.VARS_CACHE['localhost']['temp_path'] = temp_path + + # create play and do first run + play = Play(playbook, ds, basedir) + + # the second run is started by calling update_vars_files + play.update_vars_files(['localhost']) + os.remove(temp_path) + + assert 'foo' in play.playbook.VARS_CACHE['localhost'], "vars_file vars were not loaded into vars_cache" + assert play.playbook.VARS_CACHE['localhost']['foo'] == 'bar', "foo does not equal bar" + + def test_vars_files_for_host_with_extra_vars(self): + + # host != None + # vars in filename2 + # no vars in filename3 + + # make a vars file + fd, temp_path = mkstemp() + f = open(temp_path, "wb") + f.write("foo: bar\n") + f.close() + + # build play attributes + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars_files": ["{{ temp_path }}"]} + basedir = "." + playbook.VARS_CACHE['localhost']['temp_path'] = temp_path + playbook.extra_vars = {"foo": "extra"} + + # create play and do first run + play = Play(playbook, ds, basedir) + + # the second run is started by calling update_vars_files + play.update_vars_files(['localhost']) + os.remove(temp_path) + + assert 'foo' in play.vars, "extra vars were not set in play.vars" + assert 'foo' in play.playbook.VARS_CACHE['localhost'], "vars_file vars were not loaded into vars_cache" + assert play.playbook.VARS_CACHE['localhost']['foo'] == 'extra', "extra vars did not overwrite vars_files vars" + + + ######################################## + # COMPLEX FILENAME TEMPLATING TESTS + ######################################## + + def test_vars_files_two_vars_in_name(self): + + # self.vars = ds['vars'] + # self.vars += _get_vars() ... aka extra_vars + + # make a temp dir + temp_dir = mkdtemp() + + # make a temp file + fd, temp_file = mkstemp(dir=temp_dir) + f = open(temp_file, "wb") + f.write("foo: bar\n") + f.close() + + # build play attributes + playbook = FakePlayBook() + ds = { "hosts": "localhost", + "vars": { "temp_dir": os.path.dirname(temp_file), + "temp_file": os.path.basename(temp_file) }, + "vars_files": ["{{ temp_dir + '/' + temp_file }}"]} + basedir = "." + + # create play and do first run + play = Play(playbook, ds, basedir) + + # cleanup + shutil.rmtree(temp_dir) + + assert 'foo' in play.vars, "double var templated vars_files filename not loaded" + + def test_vars_files_two_vars_different_scope(self): + + # + # Use a play var and an inventory var to create the filename + # + + # self.playbook.inventory.get_variables(host) + # {'group_names': ['ungrouped'], 'inventory_hostname': 'localhost', + # 'ansible_ssh_user': 'root', 'inventory_hostname_short': 'localhost'} + + # make a temp dir + temp_dir = mkdtemp() + + # make a temp file + fd, temp_file = mkstemp(dir=temp_dir) + f = open(temp_file, "wb") + f.write("foo: bar\n") + f.close() + + # build play attributes + playbook = FakePlayBook() + playbook.inventory.hosts['localhost'] = {'inventory_hostname': os.path.basename(temp_file)} + ds = { "hosts": "localhost", + "vars": { "temp_dir": os.path.dirname(temp_file)}, + "vars_files": ["{{ temp_dir + '/' + inventory_hostname }}"]} + basedir = "." + + # create play and do first run + play = Play(playbook, ds, basedir) + + # do the host run + play.update_vars_files(['localhost']) + + # cleanup + shutil.rmtree(temp_dir) + + assert 'foo' not in play.vars, \ + "mixed scope vars_file loaded into play vars" + assert 'foo' in play.playbook.VARS_CACHE['localhost'], \ + "differently scoped templated vars_files filename not loaded" + assert play.playbook.VARS_CACHE['localhost']['foo'] == 'bar', \ + "foo is not bar" + + def test_vars_files_two_vars_different_scope_first_found(self): + + # + # Use a play var and an inventory var to create the filename + # + + # make a temp dir + temp_dir = mkdtemp() + + # make a temp file + fd, temp_file = mkstemp(dir=temp_dir) + f = open(temp_file, "wb") + f.write("foo: bar\n") + f.close() + + # build play attributes + playbook = FakePlayBook() + playbook.inventory.hosts['localhost'] = {'inventory_hostname': os.path.basename(temp_file)} + ds = { "hosts": "localhost", + "vars": { "temp_dir": os.path.dirname(temp_file)}, + "vars_files": [["{{ temp_dir + '/' + inventory_hostname }}"]]} + basedir = "." + + # create play and do first run + play = Play(playbook, ds, basedir) + + # do the host run + play.update_vars_files(['localhost']) + + # cleanup + shutil.rmtree(temp_dir) + + assert 'foo' not in play.vars, \ + "mixed scope vars_file loaded into play vars" + assert 'foo' in play.playbook.VARS_CACHE['localhost'], \ + "differently scoped templated vars_files filename not loaded" + assert play.playbook.VARS_CACHE['localhost']['foo'] == 'bar', \ + "foo is not bar" + +