def test_variable_manager_role_vars_dependencies(self): ''' Tests vars from role dependencies with duplicate dependencies. ''' v = VariableManager() v._fact_cache = defaultdict(dict) fake_loader = DictDataLoader({ # role common-role '/etc/ansible/roles/common-role/tasks/main.yml': """ - debug: msg="{{role_var}}" """, # We do not need allow_duplicates: yes for this role # because eliminating duplicates is done by the execution # strategy, which we do not test here. # role role1 '/etc/ansible/roles/role1/vars/main.yml': """ role_var: "role_var_from_role1" """, '/etc/ansible/roles/role1/meta/main.yml': """ dependencies: - { role: common-role } """, # role role2 '/etc/ansible/roles/role2/vars/main.yml': """ role_var: "role_var_from_role2" """, '/etc/ansible/roles/role2/meta/main.yml': """ dependencies: - { role: common-role } """, }) play1 = Play.load(dict( hosts=['all'], roles=['role1', 'role2'], ), loader=fake_loader, variable_manager=v) # The task defined by common-role exists twice because role1 # and role2 depend on common-role. Check that the tasks see # different values of role_var. blocks = play1.compile() task = blocks[1].block[0] res = v.get_vars(loader=fake_loader, play=play1, task=task) self.assertEqual(res['role_var'], 'role_var_from_role1') task = blocks[2].block[0] res = v.get_vars(loader=fake_loader, play=play1, task=task) self.assertEqual(res['role_var'], 'role_var_from_role2')
def test_variable_manager_group_vars_file(self): fake_loader = DictDataLoader( { "group_vars/all.yml": """ foo: bar """, "group_vars/somegroup.yml": """ bam: baz """, } ) v = VariableManager() v.add_group_vars_file("group_vars/all.yml", loader=fake_loader) v.add_group_vars_file("group_vars/somegroup.yml", loader=fake_loader) self.assertIn("somegroup", v._group_vars_files) self.assertEqual(v._group_vars_files["all"], dict(foo="bar")) self.assertEqual(v._group_vars_files["somegroup"], dict(bam="baz")) mock_group = MagicMock() mock_group.name = "somegroup" mock_group.get_ancestors.return_value = () mock_group.get_vars.return_value = dict() mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = (mock_group,) vars = v.get_vars(loader=fake_loader, host=mock_host, use_cache=False) self.assertEqual(vars.get("foo"), "bar") self.assertEqual(vars.get("bam"), "baz")
def test_manager_extra_vars(self): extra_vars = dict(a=1, b=2, c=3) v = VariableManager() v.set_extra_vars(extra_vars) self.assertEqual(v.get_vars(), extra_vars) self.assertIsNot(v.extra_vars, extra_vars)
def test_variable_manager_host_vars_file(self): fake_loader = DictDataLoader({ "host_vars/hostname1.yml": """ foo: bar """, "other_path/host_vars/hostname1.yml": """ foo: bam baa: bat """, "host_vars/host.name.yml": """ host_with_dots: true """, }) v = VariableManager() v.add_host_vars_file("host_vars/hostname1.yml", loader=fake_loader) v.add_host_vars_file("other_path/host_vars/hostname1.yml", loader=fake_loader) self.assertIn("hostname1", v._host_vars_files) self.assertEqual(v._host_vars_files["hostname1"], [dict(foo="bar"), dict(foo="bam", baa="bat")]) mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = () mock_host.get_group_vars.return_value = dict() self.assertEqual(v.get_vars(loader=fake_loader, host=mock_host, use_cache=False).get("foo"), "bam") self.assertEqual(v.get_vars(loader=fake_loader, host=mock_host, use_cache=False).get("baa"), "bat") v.add_host_vars_file("host_vars/host.name", loader=fake_loader) self.assertEqual(v._host_vars_files["host.name"], [dict(host_with_dots=True)])
def test_variable_manager_group_vars_file(self): fake_loader = DictDataLoader({ "group_vars/all.yml": """ foo: bar """, "group_vars/somegroup.yml": """ bam: baz """ }) v = VariableManager() v.add_group_vars_file("group_vars/all.yml", loader=fake_loader) v.add_group_vars_file("group_vars/somegroup.yml", loader=fake_loader) self.assertIn("somegroup", v._group_vars_files) self.assertEqual(v._group_vars_files["all"], dict(foo="bar")) self.assertEqual(v._group_vars_files["somegroup"], dict(bam="baz")) mock_group = MagicMock() mock_group.name = "somegroup" mock_group.get_ancestors.return_value = () mock_group.get_vars.return_value = dict() mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = (mock_group, ) vars = v.get_vars(loader=fake_loader, host=mock_host, use_cache=False) self.assertEqual(vars.get("foo"), "bar") self.assertEqual(vars.get("bam"), "baz")
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() vars = v.get_vars(loader=fake_loader, use_cache=False) if 'omit' in vars: del vars['omit'] if 'vars' in vars: del vars['vars'] if 'ansible_version' in vars: del vars['ansible_version'] self.assertEqual(vars, dict(playbook_dir='.')) self.assertEqual( v._merge_dicts( dict(a=1), dict(b=2) ), dict(a=1, b=2) ) self.assertEqual( v._merge_dicts( dict(a=1, c=dict(foo='bar')), dict(b=2, c=dict(baz='bam')) ), dict(a=1, b=2, c=dict(foo='bar', baz='bam')) )
def get(self): data_loader = DataLoader() # data_loader.set_vault_password('627VR8*;YU99B') variable_manager = VariableManager() extra_vars = self.console_args.extra_vars[:] configurations = [ '@' + config for config in self.cluster_config_path.split(',') ] extra_vars.append('cluster=' + get_cluster_name(self.cluster_config_path)) extra_vars.extend(configurations) options = collections.namedtuple('options', 'extra_vars') variable_manager.extra_vars = load_extra_vars( loader=data_loader, options=options(extra_vars=extra_vars)) read_variables = variable_manager.get_vars(data_loader) templar = Templar(data_loader, variables=read_variables) templar._filter_loader = self.template.filter_plugin_loader return templar.template(read_variables, fail_on_undefined=True)
def test_manager_play_vars(self): mock_play = MagicMock() mock_play.get_vars.return_value = dict(foo="bar") mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = [] v = VariableManager() self.assertEqual(v.get_vars(play=mock_play), dict(foo="bar"))
def test_variable_manager_task_vars(self): fake_loader = DictDataLoader({}) mock_task = MagicMock() mock_task.get_vars.return_value = dict(foo="bar") v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, task=mock_task).get("foo"), "bar")
def test_basic_manager(self): v = VariableManager() self.assertEqual(v.get_vars(), dict()) self.assertEqual(v._merge_dicts(dict(a=1), dict(b=2)), dict(a=1, b=2)) self.assertEqual( v._merge_dicts(dict(a=1, c=dict(foo='bar')), dict(b=2, c=dict(baz='bam'))), dict(a=1, b=2, c=dict(foo='bar', baz='bam')))
def test_variable_manager_task_vars(self): fake_loader = DictDataLoader({}) mock_task = MagicMock() mock_task._role = None mock_task.get_vars.return_value = dict(foo="bar") v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, task=mock_task, use_cache=False).get("foo"), "bar")
def test_variable_manager_play_vars(self): fake_loader = DictDataLoader({}) mock_play = MagicMock() mock_play.get_vars.return_value = dict(foo="bar") mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = [] v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, play=mock_play).get("foo"), "bar")
def test_variable_manager_play_vars(self): fake_loader = DictDataLoader({}) mock_play = MagicMock() mock_play.get_vars.return_value = dict(foo="bar") mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = [] v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, play=mock_play, use_cache=False).get("foo"), "bar")
def test_variable_manager_extra_vars(self): fake_loader = DictDataLoader({}) extra_vars = dict(a=1, b=2, c=3) v = VariableManager() v.set_extra_vars(extra_vars) for (key, val) in extra_vars.iteritems(): self.assertEqual(v.get_vars(loader=fake_loader).get(key), val) self.assertIsNot(v.extra_vars.get(key), val)
def test_variable_manager_task_vars(self): fake_loader = DictDataLoader({}) mock_task = MagicMock() mock_task._role = None mock_task.loop = None mock_task.get_vars.return_value = dict(foo="bar") mock_task.get_include_params.return_value = dict() v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, task=mock_task, use_cache=False).get("foo"), "bar")
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() vars = v.get_vars(loader=fake_loader, use_cache=False) #FIXME: not sure why we remove all and only test playbook_dir for remove in ['omit', 'vars', 'ansible_version', 'ansible_check_mode', 'ansible_playbook_python']: if remove in vars: del vars[remove] self.assertEqual(vars, dict(playbook_dir='.'))
def test_variable_manager_extra_vars(self): fake_loader = DictDataLoader({}) extra_vars = dict(a=1, b=2, c=3) v = VariableManager() v.extra_vars = extra_vars vars = v.get_vars(loader=fake_loader, use_cache=False) for (key, val) in iteritems(extra_vars): self.assertEqual(vars.get(key), val) self.assertIsNot(v.extra_vars, extra_vars)
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() vars = v.get_vars(loader=fake_loader, use_cache=False) if 'omit' in vars: del vars['omit'] if 'vars' in vars: del vars['vars'] if 'ansible_version' in vars: del vars['ansible_version'] self.assertEqual(vars, dict(playbook_dir='.'))
def test_variable_manager_extra_vars(self): fake_loader = DictDataLoader({}) extra_vars = dict(a=1, b=2, c=3) v = VariableManager() v.extra_vars = extra_vars vars = v.get_vars(loader=fake_loader, use_cache=False) for (key, val) in extra_vars.iteritems(): self.assertEqual(vars.get(key), val) self.assertIsNot(v.extra_vars, extra_vars)
def test_variable_manager_play_vars_files(self): fake_loader = DictDataLoader({ "/path/to/somefile.yml": """ foo: bar """ }) mock_play = MagicMock() mock_play.get_vars.return_value = dict() mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = ['/path/to/somefile.yml'] v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, play=mock_play).get("foo"), "bar")
def test_manager_play_vars_files(self): fake_loader = DictDataLoader({ "/path/to/somefile.yml": """ foo: bar """ }) mock_play = MagicMock() mock_play.get_vars.return_value = dict() mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = ['/path/to/somefile.yml'] v = VariableManager(loader=fake_loader) self.assertEqual(v.get_vars(play=mock_play), dict(foo="bar"))
def test_variable_manager_play_vars_files(self): fake_loader = DictDataLoader({ "/path/to/somefile.yml": """ foo: bar """ }) mock_play = MagicMock() mock_play.get_vars.return_value = dict() mock_play.get_roles.return_value = [] mock_play.get_vars_files.return_value = ['/path/to/somefile.yml'] v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader, play=mock_play, use_cache=False).get("foo"), "bar")
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() vars = v.get_vars(loader=fake_loader, use_cache=False) #FIXME: not sure why we remove all and only test playbook_dir for remove in [ 'omit', 'vars', 'ansible_version', 'ansible_check_mode', 'ansible_playbook_python' ]: if remove in vars: del vars[remove] self.assertEqual(vars, dict(playbook_dir='.'))
def test_basic_manager(self): v = VariableManager() self.assertEqual(v.get_vars(), dict()) self.assertEqual( v._merge_dicts( dict(a=1), dict(b=2) ), dict(a=1, b=2) ) self.assertEqual( v._merge_dicts( dict(a=1, c=dict(foo='bar')), dict(b=2, c=dict(baz='bam')) ), dict(a=1, b=2, c=dict(foo='bar', baz='bam')) )
def get(self): data_loader = DataLoader() # data_loader.set_vault_password() variable_manager = VariableManager() extra_vars = self.console_args.extra_vars[:] extra_vars.append('cluster=' + get_cluster_name(self.cluster_config_path)) options = collections.namedtuple('options', 'extra_vars') variable_manager.extra_vars = load_extra_vars(loader=data_loader, options=options(extra_vars=extra_vars)) variables = variable_manager.get_vars(data_loader) rendered = self.template.render(self.cluster_config_path, variables) return yaml.load(rendered)
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() vars = v.get_vars(loader=fake_loader, use_cache=False) if "omit" in vars: del vars["omit"] if "vars" in vars: del vars["vars"] self.assertEqual(vars, dict(playbook_dir=".")) self.assertEqual(v._merge_dicts(dict(a=1), dict(b=2)), dict(a=1, b=2)) self.assertEqual( v._merge_dicts(dict(a=1, c=dict(foo="bar")), dict(b=2, c=dict(baz="bam"))), dict(a=1, b=2, c=dict(foo="bar", baz="bam")), )
def test_manager_group_vars_file(self): fake_loader = DictDataLoader({ "group_vars/somegroup.yml": """ foo: bar """ }) v = VariableManager(loader=fake_loader) v.add_group_vars_file("group_vars/somegroup.yml") self.assertIn("somegroup", v._group_vars_files) self.assertEqual(v._group_vars_files["somegroup"], dict(foo="bar")) mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = ["somegroup"] self.assertEqual(v.get_vars(host=mock_host), dict(foo="bar"))
def test_variable_manager_host_vars_file(self): fake_loader = DictDataLoader({ "host_vars/hostname1.yml": """ foo: bar """ }) v = VariableManager() v.add_host_vars_file("host_vars/hostname1.yml", loader=fake_loader) self.assertIn("hostname1", v._host_vars_files) self.assertEqual(v._host_vars_files["hostname1"], dict(foo="bar")) mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = () self.assertEqual(v.get_vars(loader=fake_loader, host=mock_host).get("foo"), "bar")
def test_basic_manager(self): fake_loader = DictDataLoader({}) v = VariableManager() self.assertEqual(v.get_vars(loader=fake_loader), dict()) self.assertEqual( v._merge_dicts( dict(a=1), dict(b=2) ), dict(a=1, b=2) ) self.assertEqual( v._merge_dicts( dict(a=1, c=dict(foo='bar')), dict(b=2, c=dict(baz='bam')) ), dict(a=1, b=2, c=dict(foo='bar', baz='bam')) )
def extract_list_hosts_git(revision, path): """ Extract the hosts list from git, after deduplciating it and resolving variables """ result = [] if revision == '0000000000000000000000000000000000000000': return result try: host_content = subprocess.check_output( ['git', 'show', '%s:hosts' % revision], cwd=path) # usually, this is done when we can't check the list of hosts except subprocess.CalledProcessError: return result # beware, not portable on windows tmp_dir = tempfile.mkdtemp() tmp_file = tempfile.NamedTemporaryFile('w+', dir=tmp_dir) tmp_file.write(host_content) tmp_file.flush() os.fsync(tmp_file.fileno()) variable_manager = VariableManager() loader = DataLoader() inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=tmp_file.name) for group in inventory.get_groups(): for host in inventory.get_hosts(group): vars_host = variable_manager.get_vars(loader, host=host) result.append({ 'name': vars_host.get('ansible_ssh_host', host.name), 'ssh_args': vars_host.get('ansible_ssh_common_args', ''), 'connection': vars_host.get('ansible_connection', 'ssh') }) # for some reason, there is some kind of global cache that need to be # cleaned inventory.refresh_inventory() shutil.rmtree(tmp_dir) return result
def test_variable_manager_host_vars_file(self): fake_loader = DictDataLoader( { "host_vars/hostname1.yml": """ foo: bar """ } ) v = VariableManager() v.add_host_vars_file("host_vars/hostname1.yml", loader=fake_loader) self.assertIn("hostname1", v._host_vars_files) self.assertEqual(v._host_vars_files["hostname1"], dict(foo="bar")) mock_host = MagicMock() mock_host.get_name.return_value = "hostname1" mock_host.get_vars.return_value = dict() mock_host.get_groups.return_value = () self.assertEqual(v.get_vars(loader=fake_loader, host=mock_host, use_cache=False).get("foo"), "bar")
def play_vars(): parser.add_argument('--playbook_path', help='Playbook path', required=True) parser.add_argument('--play_name', help='Play Name', required=True) args = parser.parse_args() variable_manager = VariableManager() loader = DataLoader() # host12_vars = variable_manager.get_vars(loader=loader, host=inventory.parser.groups[args.host_name]) playbook_path = args.playbook_path if not os.path.exists(playbook_path): print('[ERROR] The playbook does not exist') sys.exit() # # Options = namedtuple('Options', ['listtags', 'listtasks', 'listhosts', 'syntax', 'connection','module_path', 'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check']) # options = Options(listtags=False, listtasks=False, listhosts=False, syntax=False, connection='ssh', module_path=None, forks=100, remote_user='******', private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=True, become_method=None, become_user='******', verbosity=None, check=False) # # # variable_manager.extra_vars = {'hosts': 'mywebserver'} # This can accomodate various other command line arguments.` # # passwords = {} # pb = Playbook.load(playbook_path, variable_manager=variable_manager, loader=loader) plays = pb.get_plays() for play in plays: if play._included_path is not None: loader.set_basedir(play._included_path) else: loader.set_basedir(pb._basedir) result = variable_manager.get_vars(loader=loader, play=play) # pbex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords) # results = pbex.run() print(json.dumps(result))
class TestIncludeRole(unittest.TestCase): def setUp(self): self.var_manager = VariableManager() self.loader = DictDataLoader({ '/etc/ansible/roles/l1/tasks/main.yml': """ - shell: echo 'hello world from l1' - include_role: name=l2 """, '/etc/ansible/roles/l1/tasks/alt.yml': """ - shell: echo 'hello world from l1 alt' - include_role: name=l2 tasks_from=alt defaults_from=alt """, '/etc/ansible/roles/l1/defaults/main.yml': """ test_variable: l1-main l1_variable: l1-main """, '/etc/ansible/roles/l1/defaults/alt.yml': """ test_variable: l1-alt l1_variable: l1-alt """, '/etc/ansible/roles/l2/tasks/main.yml': """ - shell: echo 'hello world from l2' - include_role: name=l3 """, '/etc/ansible/roles/l2/tasks/alt.yml': """ - shell: echo 'hello world from l2 alt' - include_role: name=l3 tasks_from=alt defaults_from=alt """, '/etc/ansible/roles/l2/defaults/main.yml': """ test_variable: l2-main l2_variable: l2-main """, '/etc/ansible/roles/l2/defaults/alt.yml': """ test_variable: l2-alt l2_variable: l2-alt """, '/etc/ansible/roles/l3/tasks/main.yml': """ - shell: echo 'hello world from l3' """, '/etc/ansible/roles/l3/tasks/alt.yml': """ - shell: echo 'hello world from l3 alt' """, '/etc/ansible/roles/l3/defaults/main.yml': """ test_variable: l3-main l3_variable: l3-main """, '/etc/ansible/roles/l3/defaults/alt.yml': """ test_variable: l3-alt l3_variable: l3-alt """ }) def tearDown(self): pass def get_tasks_vars(self, play, tasks): for task in flatten_tasks(tasks): role = task._role if not role: continue yield (role.get_name(), self.var_manager.get_vars(self.loader, play=play, task=task)) @patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop) def test_simple(self): """Test one-level include with default tasks and variables""" play = Play.load(dict( name="test play", hosts=['foo'], gather_facts=False, tasks=[ {'include_role': 'name=l3'} ] ), loader=self.loader, variable_manager=self.var_manager) tasks = play.compile() for role, task_vars in self.get_tasks_vars(play, tasks): self.assertEqual(task_vars.get('l3_variable'), 'l3-main') self.assertEqual(task_vars.get('test_variable'), 'l3-main') @patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop) def test_simple_alt_files(self): """Test one-level include with alternative tasks and variables""" play = Play.load(dict( name="test play", hosts=['foo'], gather_facts=False, tasks=[ {'include_role': 'name=l3 tasks_from=alt defaults_from=alt'} ] ), loader=self.loader, variable_manager=self.var_manager) tasks = play.compile() for role, task_vars in self.get_tasks_vars(play, tasks): self.assertEqual(task_vars.get('l3_variable'), 'l3-alt') self.assertEqual(task_vars.get('test_variable'), 'l3-alt') @patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop) def test_nested(self): """ Test nested includes with default tasks and variables. Variables from outer roles should be inherited, but overriden in inner roles. """ play = Play.load(dict( name="test play", hosts=['foo'], gather_facts=False, tasks=[ {'include_role': 'name=l1'} ] ), loader=self.loader, variable_manager=self.var_manager) tasks = play.compile() for role, task_vars in self.get_tasks_vars(play, tasks): # Outer-most role must not have variables from inner roles yet if role == 'l1': self.assertEqual(task_vars.get('l1_variable'), 'l1-main') self.assertEqual(task_vars.get('l2_variable'), None) self.assertEqual(task_vars.get('l3_variable'), None) self.assertEqual(task_vars.get('test_variable'), 'l1-main') # Middle role must have variables from outer role, but not inner elif role == 'l2': self.assertEqual(task_vars.get('l1_variable'), 'l1-main') self.assertEqual(task_vars.get('l2_variable'), 'l2-main') self.assertEqual(task_vars.get('l3_variable'), None) self.assertEqual(task_vars.get('test_variable'), 'l2-main') # Inner role must have variables from both outer roles elif role == 'l3': self.assertEqual(task_vars.get('l1_variable'), 'l1-main') self.assertEqual(task_vars.get('l2_variable'), 'l2-main') self.assertEqual(task_vars.get('l3_variable'), 'l3-main') self.assertEqual(task_vars.get('test_variable'), 'l3-main') @patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop) def test_nested_alt_files(self): """ Test nested includes with alternative tasks and variables. Variables from outer roles should be inherited, but overriden in inner roles. """ play = Play.load(dict( name="test play", hosts=['foo'], gather_facts=False, tasks=[ {'include_role': 'name=l1 tasks_from=alt defaults_from=alt'} ] ), loader=self.loader, variable_manager=self.var_manager) tasks = play.compile() for role, task_vars in self.get_tasks_vars(play, tasks): # Outer-most role must not have variables from inner roles yet if role == 'l1': self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') self.assertEqual(task_vars.get('l2_variable'), None) self.assertEqual(task_vars.get('l3_variable'), None) self.assertEqual(task_vars.get('test_variable'), 'l1-alt') # Middle role must have variables from outer role, but not inner elif role == 'l2': self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') self.assertEqual(task_vars.get('l2_variable'), 'l2-alt') self.assertEqual(task_vars.get('l3_variable'), None) self.assertEqual(task_vars.get('test_variable'), 'l2-alt') # Inner role must have variables from both outer roles elif role == 'l3': self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') self.assertEqual(task_vars.get('l2_variable'), 'l2-alt') self.assertEqual(task_vars.get('l3_variable'), 'l3-alt') self.assertEqual(task_vars.get('test_variable'), 'l3-alt')
class InventoryCLI(CLI): ''' used to display or dump the configured inventory as Ansible sees it ''' ARGUMENTS = {'host': 'The name of a host to match in the inventory, relevant when using --list', 'group': 'The name of a group in the inventory, relevant when using --graph', } def __init__(self, args): super(InventoryCLI, self).__init__(args) self.vm = None self.loader = None self.inventory = None self._new_api = True def parse(self): self.parser = CLI.base_parser( usage='usage: %prog [options] [host|group]', epilog='Show Ansible inventory information, by default it uses the inventory script JSON format', inventory_opts=True, vault_opts=True ) # Actions action_group = optparse.OptionGroup(self.parser, "Actions", "One of following must be used on invocation, ONLY ONE!") action_group.add_option("--list", action="store_true", default=False, dest='list', help='Output all hosts info, works as inventory script') action_group.add_option("--host", action="store", default=None, dest='host', help='Output specific host info, works as inventory script') action_group.add_option("--graph", action="store_true", default=False, dest='graph', help='create inventory graph, if supplying pattern it must be a valid group name') self.parser.add_option_group(action_group) # Options self.parser.add_option("-y", "--yaml", action="store_true", default=False, dest='yaml', help='Use YAML format instead of default JSON, ignored for --graph') self.parser.add_option("--vars", action="store_true", default=False, dest='show_vars', help='Add vars to graph display, ignored unless used with --graph') super(InventoryCLI, self).parse() display.verbosity = self.options.verbosity self.validate_conflicts(vault_opts=True) # there can be only one! and, at least, one! used = 0 for opt in (self.options.list, self.options.host, self.options.graph): if opt: used += 1 if used == 0: raise AnsibleOptionsError("No action selected, at least one of --host, --graph or --list needs to be specified.") elif used > 1: raise AnsibleOptionsError("Conflicting options used, only one of --host, --graph or --list can be used at the same time.") # set host pattern to default if not supplied if len(self.args) > 0: self.options.pattern = self.args[0] else: self.options.pattern = 'all' def run(self): results = None super(InventoryCLI, self).run() # Initialize needed objects if getattr(self, '_play_prereqs', False): self.loader, self.inventory, self.vm = self._play_prereqs(self.options) else: # fallback to pre 2.4 way of initialzing from ansible.vars import VariableManager from ansible.inventory import Inventory self._new_api = False self.loader = DataLoader() self.vm = VariableManager() # use vault if needed if self.options.vault_password_file: vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=self.loader) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords() else: vault_pass = None if vault_pass: self.loader.set_vault_password(vault_pass) # actually get inventory and vars self.inventory = Inventory(loader=self.loader, variable_manager=self.vm, host_list=self.options.inventory) self.vm.set_inventory(self.inventory) if self.options.host: hosts = self.inventory.get_hosts(self.options.host) if len(hosts) != 1: raise AnsibleOptionsError("You must pass a single valid host to --hosts parameter") myvars = self._get_host_variables(host=hosts[0]) self._remove_internal(myvars) # FIXME: should we template first? results = self.dump(myvars) elif self.options.graph: results = self.inventory_graph() elif self.options.list: top = self._get_group('all') if self.options.yaml: results = self.yaml_inventory(top) else: results = self.json_inventory(top) results = self.dump(results) if results: # FIXME: pager? display.display(results) exit(0) exit(1) def dump(self, stuff): if self.options.yaml: import yaml from ansible.parsing.yaml.dumper import AnsibleDumper results = yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False) else: import json results = json.dumps(stuff, sort_keys=True, indent=4) return results def _get_host_variables(self, host): if self._new_api: hostvars = self.vm.get_vars(host=host) else: hostvars = self.vm.get_vars(self.loader, host=host) return hostvars def _get_group(self, gname): if self._new_api: group = self.inventory.groups.get(gname) else: group = self.inventory.get_group(gname) return group def _remove_internal(self, dump): for internal in INTERNAL_VARS: if internal in dump: del dump[internal] def _remove_empty(self, dump): # remove empty keys for x in ('hosts', 'vars', 'children'): if x in dump and not dump[x]: del dump[x] def _show_vars(self, dump, depth): result = [] self._remove_internal(dump) if self.options.show_vars: for (name, val) in sorted(dump.items()): result.append(self._graph_name('{%s = %s}' % (name, val), depth + 1)) return result def _graph_name(self, name, depth=0): if depth: name = " |" * (depth) + "--%s" % name return name def _graph_group(self, group, depth=0): result = [self._graph_name('@%s:' % group.name, depth)] depth = depth + 1 for kid in sorted(group.child_groups, key=attrgetter('name')): result.extend(self._graph_group(kid, depth)) if group.name != 'all': for host in sorted(group.hosts, key=attrgetter('name')): result.append(self._graph_name(host.name, depth)) result.extend(self._show_vars(host.get_vars(), depth)) result.extend(self._show_vars(group.get_vars(), depth)) return result def inventory_graph(self): start_at = self._get_group(self.options.pattern) if start_at: return '\n'.join(self._graph_group(start_at)) else: raise AnsibleOptionsError("Pattern must be valid group name when using --graph") def json_inventory(self, top): def format_group(group): results = {} results[group.name] = {} if group.name != 'all': results[group.name]['hosts'] = [h.name for h in sorted(group.hosts, key=attrgetter('name'))] results[group.name]['vars'] = group.get_vars() results[group.name]['children'] = [] for subgroup in sorted(group.child_groups, key=attrgetter('name')): results[group.name]['children'].append(subgroup.name) results.update(format_group(subgroup)) self._remove_empty(results[group.name]) return results results = format_group(top) # populate meta results['_meta'] = {'hostvars': {}} hosts = self.inventory.get_hosts() for host in hosts: results['_meta']['hostvars'][host.name] = self._get_host_variables(host=host) self._remove_internal(results['_meta']['hostvars'][host.name]) return results def yaml_inventory(self, top): seen = [] def format_group(group): results = {} # initialize group + vars results[group.name] = {} results[group.name]['vars'] = group.get_vars() # subgroups results[group.name]['children'] = {} for subgroup in sorted(group.child_groups, key=attrgetter('name')): if subgroup.name != 'all': results[group.name]['children'].update(format_group(subgroup)) # hosts for group results[group.name]['hosts'] = {} if group.name != 'all': for h in sorted(group.hosts, key=attrgetter('name')): myvars = {} if h.name not in seen: # avoid defining host vars more than once seen.append(h.name) myvars = self._get_host_variables(host=h) self._remove_internal(myvars) results[group.name]['hosts'][h.name] = myvars self._remove_empty(results[group.name]) return results return format_group(top)
def run(self): # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None b_vault_pass = None passwords = {} # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.playbooks: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError( "the playbook: %s does not appear to be a file" % playbook) # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file b_vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=loader) loader.set_vault_password(b_vault_pass) elif self.options.ask_vault_pass: b_vault_pass = self.ask_vault_passwords() loader.set_vault_password(b_vault_pass) elif 'VAULT_PASS' in os.environ: loader.set_vault_password(os.environ['VAULT_PASS']) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() # Subspace injection option_extra_vars = load_extra_vars(loader=loader, options=self.options) option_extra_vars.update(self.extra_vars) variable_manager.extra_vars = option_extra_vars # End Subspace injection variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning( "provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # flush fact cache if requested if self.options.flush_cache: self._flush_cache(inventory, variable_manager) hosts = inventory.get_hosts() if self.options.subset and not hosts: raise NoValidHosts( "The limit <%s> is not included in the inventory: %s" % (self.options.subset, inventory.host_list)) # create the playbook executor, which manages running the plays via a task queue manager # Subspace injection pbex = PlaybookExecutor(playbooks=self.playbooks, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) playbook_map = self._get_playbook_map() pbex._tqm._stats = SubspaceAggregateStats(playbook_map) pbex._tqm.load_callbacks() pbex._tqm.send_callback( 'start_logging', logger=self.options.logger, username=self.extra_vars.get('ATMOUSERNAME', "No-User"), ) for host in inventory._subset: variables = inventory.get_vars(host) self.options.logger.info("Vars found for hostname %s: %s" % (host, variables)) # End Subspace injection results = pbex.run() # Subspace injection stats = pbex._tqm._stats self.stats = stats # Nonpersistent fact cache stores 'register' variables. We would like # to get access to stdout/stderr for specific commands and relay # some of that information back to the end user. self.results = dict(pbex._variable_manager._nonpersistent_fact_cache) # End Subspace injection if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): if play._included_path is not None: loader.set_basedir(play._included_path) else: pb_dir = os.path.realpath( os.path.dirname(p['playbook'])) loader.set_basedir(pb_dir) msg = "\n play #%d (%s): %s" % (idx + 1, ','.join( play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % ( play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list( mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name( ) else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join( cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks( play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join( cur_tags) display.display(taskmsg) return 0 else: return results
def test_manager_task_vars(self): mock_task = MagicMock() mock_task.get_vars.return_value = dict(foo="bar") v = VariableManager() self.assertEqual(v.get_vars(task=mock_task), dict(foo="bar"))
class InventoryCLI(CLI): ''' used to display or dump the configured inventory as Ansible sees it ''' ARGUMENTS = { 'host': 'The name of a host to match in the inventory, relevant when using --list', 'group': 'The name of a group in the inventory, relevant when using --graph', } def __init__(self, args): super(InventoryCLI, self).__init__(args) self.vm = None self.loader = None self.inventory = None self._new_api = True def parse(self): self.parser = CLI.base_parser( usage='usage: %prog [options] [host|group]', epilog= 'Show Ansible inventory information, by default it uses the inventory script JSON format', inventory_opts=True, vault_opts=True, basedir_opts=True, ) # remove unused default options self.parser.remove_option('--limit') self.parser.remove_option('--list-hosts') # Actions action_group = optparse.OptionGroup( self.parser, "Actions", "One of following must be used on invocation, ONLY ONE!") action_group.add_option( "--list", action="store_true", default=False, dest='list', help='Output all hosts info, works as inventory script') action_group.add_option( "--host", action="store", default=None, dest='host', help='Output specific host info, works as inventory script') action_group.add_option( "--graph", action="store_true", default=False, dest='graph', help= 'create inventory graph, if supplying pattern it must be a valid group name' ) self.parser.add_option_group(action_group) # graph self.parser.add_option( "-y", "--yaml", action="store_true", default=False, dest='yaml', help='Use YAML format instead of default JSON, ignored for --graph' ) self.parser.add_option( "--vars", action="store_true", default=False, dest='show_vars', help='Add vars to graph display, ignored unless used with --graph') # list self.parser.add_option( "--export", action="store_true", default=C.INVENTORY_EXPORT, dest='export', help= "When doing an --list, represent in a way that is optimized for export," "not as an accurate representation of how Ansible has processed it" ) # self.parser.add_option("--ignore-vars-plugins", action="store_true", default=False, dest='ignore_vars_plugins', # help="When doing an --list, skip vars data from vars plugins, by default, this would include group_vars/ and host_vars/") super(InventoryCLI, self).parse() display.verbosity = self.options.verbosity self.validate_conflicts(vault_opts=True) # there can be only one! and, at least, one! used = 0 for opt in (self.options.list, self.options.host, self.options.graph): if opt: used += 1 if used == 0: raise AnsibleOptionsError( "No action selected, at least one of --host, --graph or --list needs to be specified." ) elif used > 1: raise AnsibleOptionsError( "Conflicting options used, only one of --host, --graph or --list can be used at the same time." ) # set host pattern to default if not supplied if len(self.args) > 0: self.options.pattern = self.args[0] else: self.options.pattern = 'all' def run(self): results = None super(InventoryCLI, self).run() # Initialize needed objects if getattr(self, '_play_prereqs', False): self.loader, self.inventory, self.vm = self._play_prereqs( self.options) else: # fallback to pre 2.4 way of initialzing from ansible.vars import VariableManager from ansible.inventory import Inventory self._new_api = False self.loader = DataLoader() self.vm = VariableManager() # use vault if needed if self.options.vault_password_file: vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=self.loader) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords() else: vault_pass = None if vault_pass: self.loader.set_vault_password(vault_pass) # actually get inventory and vars self.inventory = Inventory(loader=self.loader, variable_manager=self.vm, host_list=self.options.inventory) self.vm.set_inventory(self.inventory) if self.options.host: hosts = self.inventory.get_hosts(self.options.host) if len(hosts) != 1: raise AnsibleOptionsError( "You must pass a single valid host to --hosts parameter") myvars = self._get_host_variables(host=hosts[0]) self._remove_internal(myvars) # FIXME: should we template first? results = self.dump(myvars) elif self.options.graph: results = self.inventory_graph() elif self.options.list: top = self._get_group('all') if self.options.yaml: results = self.yaml_inventory(top) else: results = self.json_inventory(top) results = self.dump(results) if results: # FIXME: pager? display.display(results) exit(0) exit(1) def dump(self, stuff): if self.options.yaml: import yaml from ansible.parsing.yaml.dumper import AnsibleDumper results = yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False) else: import json from ansible.parsing.ajson import AnsibleJSONEncoder results = json.dumps(stuff, cls=AnsibleJSONEncoder, sort_keys=True, indent=4) return results # FIXME: refactor to use same for VM def get_plugin_vars(self, path, entity): data = {} def _get_plugin_vars(plugin, path, entities): data = {} try: data = plugin.get_vars(self.loader, path, entity) except AttributeError: try: if isinstance(entity, Host): data = combine_vars(data, plugin.get_host_vars(entity.name)) else: data = combine_vars(data, plugin.get_group_vars(entity.name)) except AttributeError: if hasattr(plugin, 'run'): raise AnsibleError( "Cannot use v1 type vars plugin %s from %s" % (plugin._load_name, plugin._original_path)) else: raise AnsibleError( "Invalid vars plugin %s from %s" % (plugin._load_name, plugin._original_path)) return data for plugin in vars_loader.all(): data = combine_vars(data, _get_plugin_vars(plugin, path, entity)) return data def _get_group_variables(self, group): # get info from inventory source res = group.get_vars() # FIXME: add switch to skip vars plugins, add vars plugin info for inventory_dir in self.inventory._sources: res = combine_vars(res, self.get_plugin_vars(inventory_dir, group)) if group.priority != 1: res['ansible_group_priority'] = group.priority return res def _get_host_variables(self, host): if self.options.export: hostvars = host.get_vars() # FIXME: add switch to skip vars plugins # add vars plugin info for inventory_dir in self.inventory._sources: hostvars = combine_vars( hostvars, self.get_plugin_vars(inventory_dir, host)) else: if self._new_api: hostvars = self.vm.get_vars(host=host, include_hostvars=False) else: hostvars = self.vm.get_vars(self.loader, host=host, include_hostvars=False) return hostvars def _get_group(self, gname): if self._new_api: group = self.inventory.groups.get(gname) else: group = self.inventory.get_group(gname) return group def _remove_internal(self, dump): for internal in INTERNAL_VARS: if internal in dump: del dump[internal] def _remove_empty(self, dump): # remove empty keys for x in ('hosts', 'vars', 'children'): if x in dump and not dump[x]: del dump[x] def _show_vars(self, dump, depth): result = [] self._remove_internal(dump) if self.options.show_vars: for (name, val) in sorted(dump.items()): result.append( self._graph_name('{%s = %s}' % (name, val), depth)) return result def _graph_name(self, name, depth=0): if depth: name = " |" * (depth) + "--%s" % name return name def _graph_group(self, group, depth=0): result = [self._graph_name('@%s:' % group.name, depth)] depth = depth + 1 for kid in sorted(group.child_groups, key=attrgetter('name')): result.extend(self._graph_group(kid, depth)) if group.name != 'all': for host in sorted(group.hosts, key=attrgetter('name')): result.append(self._graph_name(host.name, depth)) result.extend(self._show_vars(host.get_vars(), depth + 1)) result.extend(self._show_vars(self._get_group_variables(group), depth)) return result def inventory_graph(self): start_at = self._get_group(self.options.pattern) if start_at: return '\n'.join(self._graph_group(start_at)) else: raise AnsibleOptionsError( "Pattern must be valid group name when using --graph") def json_inventory(self, top): def format_group(group): results = {} results[group.name] = {} if group.name != 'all': results[group.name]['hosts'] = [ h.name for h in sorted(group.hosts, key=attrgetter('name')) ] results[group.name]['children'] = [] for subgroup in sorted(group.child_groups, key=attrgetter('name')): results[group.name]['children'].append(subgroup.name) results.update(format_group(subgroup)) if self.options.export: results[group.name]['vars'] = self._get_group_variables(group) self._remove_empty(results[group.name]) return results results = format_group(top) # populate meta results['_meta'] = {'hostvars': {}} hosts = self.inventory.get_hosts() for host in hosts: hvars = self._get_host_variables(host) if hvars: self._remove_internal(hvars) results['_meta']['hostvars'][host.name] = hvars return results def yaml_inventory(self, top): seen = [] def format_group(group): results = {} # initialize group + vars results[group.name] = {} # subgroups results[group.name]['children'] = {} for subgroup in sorted(group.child_groups, key=attrgetter('name')): if subgroup.name != 'all': results[group.name]['children'].update( format_group(subgroup)) # hosts for group results[group.name]['hosts'] = {} if group.name != 'all': for h in sorted(group.hosts, key=attrgetter('name')): myvars = {} if h.name not in seen: # avoid defining host vars more than once seen.append(h.name) myvars = self._get_host_variables(host=h) self._remove_internal(myvars) results[group.name]['hosts'][h.name] = myvars if self.options.export: gvars = self._get_group_variables(group) if gvars: results[group.name]['vars'] = gvars self._remove_empty(results[group.name]) return results return format_group(top)
def test_variable_manager_precedence(self, mock_basedir): ''' Tests complex variations and combinations of get_vars() with different objects to modify the context under which variables are merged. ''' v = VariableManager() v._fact_cache = defaultdict(dict) fake_loader = DictDataLoader({ # inventory1 '/etc/ansible/inventory1': """ [group2:children] group1 [group1] host1 host_var=host_var_from_inventory_host1 [group1:vars] group_var = group_var_from_inventory_group1 [group2:vars] group_var = group_var_from_inventory_group2 """, # role defaults_only1 '/etc/ansible/roles/defaults_only1/defaults/main.yml': """ default_var: "default_var_from_defaults_only1" host_var: "host_var_from_defaults_only1" group_var: "group_var_from_defaults_only1" group_var_all: "group_var_all_from_defaults_only1" extra_var: "extra_var_from_defaults_only1" """, '/etc/ansible/roles/defaults_only1/tasks/main.yml': """ - debug: msg="here i am" """, # role defaults_only2 '/etc/ansible/roles/defaults_only2/defaults/main.yml': """ default_var: "default_var_from_defaults_only2" host_var: "host_var_from_defaults_only2" group_var: "group_var_from_defaults_only2" group_var_all: "group_var_all_from_defaults_only2" extra_var: "extra_var_from_defaults_only2" """, }) mock_basedir.return_value = './' inv1 = Inventory(loader=fake_loader, variable_manager=v, host_list='/etc/ansible/inventory1') inv1.set_playbook_basedir('./') play1 = Play.load(dict( hosts=['all'], roles=['defaults_only1', 'defaults_only2'], ), loader=fake_loader, variable_manager=v) # first we assert that the defaults as viewed as a whole are the merged results # of the defaults from each role, with the last role defined "winning" when # there is a variable naming conflict res = v.get_vars(loader=fake_loader, play=play1) self.assertEqual(res['default_var'], 'default_var_from_defaults_only2') # next, we assert that when vars are viewed from the context of a task within a # role, that task will see its own role defaults before any other role's blocks = play1.compile() task = blocks[1].block[0] res = v.get_vars(loader=fake_loader, play=play1, task=task) self.assertEqual(res['default_var'], 'default_var_from_defaults_only1') # next we assert the precendence of inventory variables v.set_inventory(inv1) h1 = inv1.get_host('host1') res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['group_var'], 'group_var_from_inventory_group1') self.assertEqual(res['host_var'], 'host_var_from_inventory_host1') # next we test with group_vars/ files loaded fake_loader.push("/etc/ansible/group_vars/all", """ group_var_all: group_var_all_from_group_vars_all """) fake_loader.push("/etc/ansible/group_vars/group1", """ group_var: group_var_from_group_vars_group1 """) fake_loader.push("/etc/ansible/group_vars/group3", """ # this is a dummy, which should not be used anywhere group_var: group_var_from_group_vars_group3 """) fake_loader.push("/etc/ansible/host_vars/host1", """ host_var: host_var_from_host_vars_host1 """) fake_loader.push("group_vars/group1", """ playbook_group_var: playbook_group_var """) fake_loader.push("host_vars/host1", """ playbook_host_var: playbook_host_var """) v.add_group_vars_file("/etc/ansible/group_vars/all", loader=fake_loader) v.add_group_vars_file("/etc/ansible/group_vars/group1", loader=fake_loader) v.add_group_vars_file("/etc/ansible/group_vars/group2", loader=fake_loader) v.add_group_vars_file("group_vars/group1", loader=fake_loader) v.add_host_vars_file("/etc/ansible/host_vars/host1", loader=fake_loader) v.add_host_vars_file("host_vars/host1", loader=fake_loader) res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['group_var'], 'group_var_from_group_vars_group1') self.assertEqual(res['group_var_all'], 'group_var_all_from_group_vars_all') self.assertEqual(res['playbook_group_var'], 'playbook_group_var') self.assertEqual(res['host_var'], 'host_var_from_host_vars_host1') self.assertEqual(res['playbook_host_var'], 'playbook_host_var') # add in the fact cache v._fact_cache['host1'] = dict(fact_cache_var="fact_cache_var_from_fact_cache") res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['fact_cache_var'], 'fact_cache_var_from_fact_cache')
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} loader = DataLoader() variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) # create the inventory, and filter it based on the subset specified (if any) hostlist = self.translate_inventory_itsm_to_ansible(self.options.inventory) pt = self.creaate_palybook_target(self.options.inventory) task_id = self.get_task_id(self.options.inventory) playbook_location = json.loads(self.options.inventory)["playbook"] inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=hostlist) variable_manager.set_inventory(inventory) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning("provided hosts list is empty, only localhost is available") no_hosts = True if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=[playbook_location], inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords, pt=pt, task_id=task_id) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join(play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks(play_context, all_vars) if not block.has_tasks(): continue for task in block.block: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list(mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name() else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join(cur_tags) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join(cur_tags) display.display(taskmsg) return 0 else: return results
def test_variable_manager_precedence(self, mock_basedir): ''' Tests complex variations and combinations of get_vars() with different objects to modify the context under which variables are merged. ''' v = VariableManager() v._fact_cache = defaultdict(dict) fake_loader = DictDataLoader({ # inventory1 '/etc/ansible/inventory1': """ [group2:children] group1 [group1] host1 host_var=host_var_from_inventory_host1 [group1:vars] group_var = group_var_from_inventory_group1 [group2:vars] group_var = group_var_from_inventory_group2 """, # role defaults_only1 '/etc/ansible/roles/defaults_only1/defaults/main.yml': """ default_var: "default_var_from_defaults_only1" host_var: "host_var_from_defaults_only1" group_var: "group_var_from_defaults_only1" group_var_all: "group_var_all_from_defaults_only1" extra_var: "extra_var_from_defaults_only1" """, '/etc/ansible/roles/defaults_only1/tasks/main.yml': """ - debug: msg="here i am" """, # role defaults_only2 '/etc/ansible/roles/defaults_only2/defaults/main.yml': """ default_var: "default_var_from_defaults_only2" host_var: "host_var_from_defaults_only2" group_var: "group_var_from_defaults_only2" group_var_all: "group_var_all_from_defaults_only2" extra_var: "extra_var_from_defaults_only2" """, }) mock_basedir.return_value = './' inv1 = Inventory(loader=fake_loader, variable_manager=v, host_list='/etc/ansible/inventory1') inv1.set_playbook_basedir('./') play1 = Play.load(dict( hosts=['all'], roles=['defaults_only1', 'defaults_only2'], ), loader=fake_loader, variable_manager=v) # first we assert that the defaults as viewed as a whole are the merged results # of the defaults from each role, with the last role defined "winning" when # there is a variable naming conflict res = v.get_vars(loader=fake_loader, play=play1) self.assertEqual(res['default_var'], 'default_var_from_defaults_only2') # next, we assert that when vars are viewed from the context of a task within a # role, that task will see its own role defaults before any other role's blocks = play1.compile() task = blocks[1].block[0] res = v.get_vars(loader=fake_loader, play=play1, task=task) self.assertEqual(res['default_var'], 'default_var_from_defaults_only1') # next we assert the precendence of inventory variables v.set_inventory(inv1) h1 = inv1.get_host('host1') res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['group_var'], 'group_var_from_inventory_group1') self.assertEqual(res['host_var'], 'host_var_from_inventory_host1') # next we test with group_vars/ files loaded fake_loader.push( "/etc/ansible/group_vars/all", """ group_var_all: group_var_all_from_group_vars_all """) fake_loader.push( "/etc/ansible/group_vars/group1", """ group_var: group_var_from_group_vars_group1 """) fake_loader.push( "/etc/ansible/group_vars/group3", """ # this is a dummy, which should not be used anywhere group_var: group_var_from_group_vars_group3 """) fake_loader.push( "/etc/ansible/host_vars/host1", """ host_var: host_var_from_host_vars_host1 """) v.add_group_vars_file("/etc/ansible/group_vars/all", loader=fake_loader) v.add_group_vars_file("/etc/ansible/group_vars/group1", loader=fake_loader) v.add_group_vars_file("/etc/ansible/group_vars/group2", loader=fake_loader) v.add_host_vars_file("/etc/ansible/host_vars/host1", loader=fake_loader) res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['group_var'], 'group_var_from_group_vars_group1') self.assertEqual(res['group_var_all'], 'group_var_all_from_group_vars_all') self.assertEqual(res['host_var'], 'host_var_from_host_vars_host1') # add in the fact cache v._fact_cache['host1'] = dict( fact_cache_var="fact_cache_var_from_fact_cache") res = v.get_vars(loader=fake_loader, play=play1, host=h1) self.assertEqual(res['fact_cache_var'], 'fact_cache_var_from_fact_cache')
def list_tags(): # ansible playbook specific opts # parser.add_argument('--list-tasks', dest='listtasks', action='store_true', # help="list all tasks that would be executed") # parser.add_argument('--list-tags', dest='listtags', action='store_true', # help="list all available tags") # parser.add_argument('--step', dest='step', action='store_true', # help="one-step-at-a-time: confirm each task before running") # parser.add_argument('--start-at-task', dest='start_at_task', # help="start the playbook at the task matching this name") # # parser.add_argument('--inventory_file', help='Inventory Filename', required=True) # parser.add_argument('--playbook_path', help='Inventory Filename', required=True) parser = CLI.base_parser( usage="%prog playbook.yml", connect_opts=True, meta_opts=True, runas_opts=True, subset_opts=True, check_opts=True, inventory_opts=True, runtask_opts=True, vault_opts=True, fork_opts=True, module_opts=True, ) # ansible playbook specific opts parser.add_option('--list-tasks', dest='listtasks', action='store_true', help="list all tasks that would be executed") parser.add_option('--list-tags', dest='listtags', action='store_true', help="list all available tags") parser.add_option( '--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") parser.add_option('--start-at-task', dest='start_at_task', help="start the playbook at the task matching this name") options, args = parser.parse_args(args[1:]) # options = parser.parse_args() inventory_path = options.inventory_file playbook_path = options.playbook_path if not os.path.exists(playbook_path): print('[ERROR] The playbook does not exist') sys.exit(1) loader = DataLoader() # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor # for playbook in playbooks: # if not os.path.exists(playbook): # raise Exception("the playbook: %s could not be found" % playbook) # if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): # raise Exception("the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() # variable_manager.extra_vars = load_extra_vars(loader=loader, options=options) # variable_manager.options_vars = load_options_vars(options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=inventory_path) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory print("provided hosts list is empty, only localhost is available") no_hosts = True # inventory.subset(options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise Exception("Specified --limit does not match any hosts") # flush fact cache if requested # if options.flush_cache: # for host in inventory.list_hosts(): # variable_manager.clear_facts(host) passwords = {} # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: print('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join( play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % ( play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host print(msg) all_tags = set() if options.listtags or options.listtasks: taskmsg = '' if options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if options.listtasks: cur_tags = list( mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name() else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join( cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=options) for block in play.compile(): block = block.filter_tagged_tasks( play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join( cur_tags) print(taskmsg)
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = { 'conn_pass': sshpass, 'become_pass': becomepass } loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=loader) loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] loader.set_vault_password(vault_pass) # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError("the playbook: %s does not appear to be a file" % playbook) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning("provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join(play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list(mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name() else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join(cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks(play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join(cur_tags) display.display(taskmsg) return 0 else: return results
def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # Manage passwords sshpass = None becomepass = None vault_pass = None passwords = {} # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor for playbook in self.args: if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError( "the playbook: %s does not appear to be a file" % playbook) # don't deal with privilege escalation or passwords when we don't need to if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax: self.normalize_become_options() (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} loader = DataLoader() if self.options.vault_password_file: # read vault_pass from a file vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=loader) loader.set_vault_password(vault_pass) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords()[0] loader.set_vault_password(vault_pass) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager() variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options) variable_manager.options_vars = load_options_vars(self.options) # create the inventory, and filter it based on the subset specified (if any) inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory) variable_manager.set_inventory(inventory) # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory display.warning( "provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: # Invalid limit raise AnsibleError("Specified --limit does not match any hosts") # flush fact cache if requested if self.options.flush_cache: for host in inventory.list_hosts(): variable_manager.clear_facts(host) # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): msg = "\n play #%d (%s): %s" % (idx + 1, ','.join( play.hosts), play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if self.options.listhosts: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % ( play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if self.options.listtags or self.options.listtasks: taskmsg = '' if self.options.listtasks: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action == 'meta': continue all_tags.update(task.tags) if self.options.listtasks: cur_tags = list( mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name( ) else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join( cur_tags) return taskmsg all_vars = variable_manager.get_vars(loader=loader, play=play) play_context = PlayContext(play=play, options=self.options) for block in play.compile(): block = block.filter_tagged_tasks( play_context, all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if self.options.listtags: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join( cur_tags) display.display(taskmsg) return 0 else: return results
class InventoryCLI(CLI): ''' used to display or dump the configured inventory as Ansible sees it ''' ARGUMENTS = { 'host': 'The name of a host to match in the inventory, relevant when using --list', 'group': 'The name of a group in the inventory, relevant when using --graph', } def __init__(self, args): super(InventoryCLI, self).__init__(args) self.args = args self.vm = None self.loader = None self.inventory = None self._new_api = True def parse(self): self.parser = CLI.base_parser( usage='usage: %prog [options] [host|group]', epilog= 'Show Ansible inventory information, by default it uses the inventory script JSON format', inventory_opts=True, vault_opts=True) self.parser.add_option( "--optimize", action="store_true", default=False, dest='optimize', help='Output variables on the group or host where they are defined' ) # Actions action_group = optparse.OptionGroup( self.parser, "Actions", "One of following must be used on invocation, ONLY ONE!") action_group.add_option( "--list", action="store_true", default=False, dest='list', help='Output all hosts info, works as inventory script') action_group.add_option( "--host", action="store", default=None, dest='host', help='Output specific host info, works as inventory script') action_group.add_option( "--graph", action="store_true", default=False, dest='graph', help= 'create inventory graph, if supplying pattern it must be a valid group name' ) self.parser.add_option_group(action_group) # Options self.parser.add_option( "-y", "--yaml", action="store_true", default=False, dest='yaml', help='Use YAML format instead of default JSON, ignored for --graph' ) self.parser.add_option( "--vars", action="store_true", default=False, dest='show_vars', help='Add vars to graph display, ignored unless used with --graph') try: super(InventoryCLI, self).parse() except Exception as e: if 'Need to implement!' not in e.args[0]: raise # --- Start of 2.3+ super(InventoryCLI, self).parse() --- self.options, self.args = self.parser.parse_args(self.args[1:]) # --- End of 2.3+ super(InventoryCLI, self).parse() --- display.verbosity = self.options.verbosity self.validate_conflicts(vault_opts=True) # there can be only one! and, at least, one! used = 0 for opt in (self.options.list, self.options.host, self.options.graph): if opt: used += 1 if used == 0: raise AnsibleOptionsError( "No action selected, at least one of --host, --graph or --list needs to be specified." ) elif used > 1: raise AnsibleOptionsError( "Conflicting options used, only one of --host, --graph or --list can be used at the same time." ) # set host pattern to default if not supplied if len(self.args) > 0: self.options.pattern = self.args[0] else: self.options.pattern = 'all' def run(self): results = None super(InventoryCLI, self).run() # Initialize needed objects if getattr(self, '_play_prereqs', False): self.loader, self.inventory, self.vm = self._play_prereqs( self.options) else: # fallback to pre 2.4 way of initialzing from ansible.vars import VariableManager from ansible.inventory import Inventory self._new_api = False self.loader = DataLoader() self.vm = VariableManager() # use vault if needed if self.options.vault_password_file: vault_pass = CLI.read_vault_password_file( self.options.vault_password_file, loader=self.loader) elif self.options.ask_vault_pass: vault_pass = self.ask_vault_passwords() else: vault_pass = None if vault_pass: self.loader.set_vault_password(vault_pass) # actually get inventory and vars self.inventory = Inventory(loader=self.loader, variable_manager=self.vm, host_list=self.options.inventory) self.vm.set_inventory(self.inventory) if self.options.host: hosts = self.inventory.get_hosts(self.options.host) if len(hosts) != 1: raise AnsibleOptionsError( "You must pass a single valid host to --hosts parameter") myvars = self._get_host_variables(host=hosts[0]) self._remove_internal(myvars) # FIXME: should we template first? results = self.dump(myvars) elif self.options.graph: results = self.inventory_graph() elif self.options.list: top = self._get_group('all') if self.options.yaml: results = self.yaml_inventory(top) else: results = self.json_inventory(top) results = self.dump(results) if results: # FIXME: pager? display.display(results) exit(0) exit(1) def dump(self, stuff): if self.options.yaml: import yaml from ansible.parsing.yaml.dumper import AnsibleDumper results = yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False) else: import json results = json.dumps(stuff, sort_keys=True, indent=4) return results def _get_host_variables(self, host): if self._new_api: hostvars = self.vm.get_vars(host=host) else: hostvars = self.vm.get_vars(self.loader, host=host) return hostvars def _get_group(self, gname): if self._new_api: group = self.inventory.groups.get(gname) else: group = self.inventory.get_group(gname) return group def _remove_internal(self, dump): for internal in INTERNAL_VARS: if internal in dump: del dump[internal] def _remove_empty(self, dump): # remove empty keys for x in ('hosts', 'vars', 'children'): if x in dump and not dump[x]: del dump[x] def _show_vars(self, dump, depth): result = [] self._remove_internal(dump) if self.options.show_vars: for (name, val) in sorted(dump.items()): result.append( self._graph_name('{%s = %s}' % (name, val), depth + 1)) return result def _graph_name(self, name, depth=0): if depth: name = " |" * (depth) + "--%s" % name return name def _graph_group(self, group, depth=0): result = [self._graph_name('@%s:' % group.name, depth)] depth = depth + 1 for kid in sorted(group.child_groups, key=attrgetter('name')): result.extend(self._graph_group(kid, depth)) if group.name != 'all': for host in sorted(group.hosts, key=attrgetter('name')): result.append(self._graph_name(host.name, depth)) result.extend(self._show_vars(host.get_vars(), depth)) result.extend(self._show_vars(group.get_vars(), depth)) return result def inventory_graph(self): start_at = self._get_group(self.options.pattern) if start_at: return '\n'.join(self._graph_group(start_at)) else: raise AnsibleOptionsError( "Pattern must be valid group name when using --graph") def json_inventory(self, top): def format_group(group): results = {} results[group.name] = {} if group.name != 'all': results[group.name]['hosts'] = [ h.name for h in sorted(group.hosts, key=attrgetter('name')) ] results[group.name]['vars'] = group.get_vars() results[group.name]['children'] = [] for subgroup in sorted(group.child_groups, key=attrgetter('name')): results[group.name]['children'].append(subgroup.name) results.update(format_group(subgroup)) self._remove_empty(results[group.name]) return results results = format_group(top) # populate meta results['_meta'] = {'hostvars': {}} hosts = self.inventory.get_hosts() for host in hosts: results['_meta']['hostvars'][host.name] = self._get_host_variables( host=host) self._remove_internal(results['_meta']['hostvars'][host.name]) return results def yaml_inventory(self, top): seen = [] def format_group(group): results = {} # initialize group + vars results[group.name] = {} results[group.name]['vars'] = group.get_vars() # subgroups results[group.name]['children'] = {} for subgroup in sorted(group.child_groups, key=attrgetter('name')): if subgroup.name != 'all': results[group.name]['children'].update( format_group(subgroup)) # hosts for group results[group.name]['hosts'] = {} if group.name != 'all': for h in sorted(group.hosts, key=attrgetter('name')): myvars = {} if h.name not in seen: # avoid defining host vars more than once seen.append(h.name) myvars = self._get_host_variables(host=h) self._remove_internal(myvars) results[group.name]['hosts'][h.name] = myvars self._remove_empty(results[group.name]) return results return format_group(top)