1# (c) 2016, Daniel Miranda <danielkza2@gmail.com> 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17 18# Make coding more python3-ish 19from __future__ import (absolute_import, division, print_function) 20__metaclass__ = type 21 22from units.compat import unittest 23from units.compat.mock import patch 24 25from ansible.playbook import Play 26from ansible.playbook.role_include import IncludeRole 27from ansible.playbook.task import Task 28from ansible.vars.manager import VariableManager 29 30from units.mock.loader import DictDataLoader 31from units.mock.path import mock_unfrackpath_noop 32 33 34class TestIncludeRole(unittest.TestCase): 35 36 def setUp(self): 37 38 self.loader = DictDataLoader({ 39 '/usr/local/etc/ansible/roles/l1/tasks/main.yml': """ 40 - shell: echo 'hello world from l1' 41 - include_role: name=l2 42 """, 43 '/usr/local/etc/ansible/roles/l1/tasks/alt.yml': """ 44 - shell: echo 'hello world from l1 alt' 45 - include_role: name=l2 tasks_from=alt defaults_from=alt 46 """, 47 '/usr/local/etc/ansible/roles/l1/defaults/main.yml': """ 48 test_variable: l1-main 49 l1_variable: l1-main 50 """, 51 '/usr/local/etc/ansible/roles/l1/defaults/alt.yml': """ 52 test_variable: l1-alt 53 l1_variable: l1-alt 54 """, 55 '/usr/local/etc/ansible/roles/l2/tasks/main.yml': """ 56 - shell: echo 'hello world from l2' 57 - include_role: name=l3 58 """, 59 '/usr/local/etc/ansible/roles/l2/tasks/alt.yml': """ 60 - shell: echo 'hello world from l2 alt' 61 - include_role: name=l3 tasks_from=alt defaults_from=alt 62 """, 63 '/usr/local/etc/ansible/roles/l2/defaults/main.yml': """ 64 test_variable: l2-main 65 l2_variable: l2-main 66 """, 67 '/usr/local/etc/ansible/roles/l2/defaults/alt.yml': """ 68 test_variable: l2-alt 69 l2_variable: l2-alt 70 """, 71 '/usr/local/etc/ansible/roles/l3/tasks/main.yml': """ 72 - shell: echo 'hello world from l3' 73 """, 74 '/usr/local/etc/ansible/roles/l3/tasks/alt.yml': """ 75 - shell: echo 'hello world from l3 alt' 76 """, 77 '/usr/local/etc/ansible/roles/l3/defaults/main.yml': """ 78 test_variable: l3-main 79 l3_variable: l3-main 80 """, 81 '/usr/local/etc/ansible/roles/l3/defaults/alt.yml': """ 82 test_variable: l3-alt 83 l3_variable: l3-alt 84 """ 85 }) 86 87 self.var_manager = VariableManager(loader=self.loader) 88 89 def tearDown(self): 90 pass 91 92 def flatten_tasks(self, tasks): 93 for task in tasks: 94 if isinstance(task, IncludeRole): 95 blocks, handlers = task.get_block_list(loader=self.loader) 96 for block in blocks: 97 for t in self.flatten_tasks(block.block): 98 yield t 99 elif isinstance(task, Task): 100 yield task 101 else: 102 for t in self.flatten_tasks(task.block): 103 yield t 104 105 def get_tasks_vars(self, play, tasks): 106 for task in self.flatten_tasks(tasks): 107 role = task._role 108 if not role: 109 continue 110 111 yield (role.get_name(), 112 self.var_manager.get_vars(play=play, task=task)) 113 114 @patch('ansible.playbook.role.definition.unfrackpath', 115 mock_unfrackpath_noop) 116 def test_simple(self): 117 118 """Test one-level include with default tasks and variables""" 119 120 play = Play.load(dict( 121 name="test play", 122 hosts=['foo'], 123 gather_facts=False, 124 tasks=[ 125 {'include_role': 'name=l3'} 126 ] 127 ), loader=self.loader, variable_manager=self.var_manager) 128 129 tasks = play.compile() 130 tested = False 131 for role, task_vars in self.get_tasks_vars(play, tasks): 132 tested = True 133 self.assertEqual(task_vars.get('l3_variable'), 'l3-main') 134 self.assertEqual(task_vars.get('test_variable'), 'l3-main') 135 self.assertTrue(tested) 136 137 @patch('ansible.playbook.role.definition.unfrackpath', 138 mock_unfrackpath_noop) 139 def test_simple_alt_files(self): 140 141 """Test one-level include with alternative tasks and variables""" 142 143 play = Play.load(dict( 144 name="test play", 145 hosts=['foo'], 146 gather_facts=False, 147 tasks=[{'include_role': 'name=l3 tasks_from=alt defaults_from=alt'}]), 148 loader=self.loader, variable_manager=self.var_manager) 149 150 tasks = play.compile() 151 tested = False 152 for role, task_vars in self.get_tasks_vars(play, tasks): 153 tested = True 154 self.assertEqual(task_vars.get('l3_variable'), 'l3-alt') 155 self.assertEqual(task_vars.get('test_variable'), 'l3-alt') 156 self.assertTrue(tested) 157 158 @patch('ansible.playbook.role.definition.unfrackpath', 159 mock_unfrackpath_noop) 160 def test_nested(self): 161 162 """ 163 Test nested includes with default tasks and variables. 164 165 Variables from outer roles should be inherited, but overridden in inner 166 roles. 167 """ 168 169 play = Play.load(dict( 170 name="test play", 171 hosts=['foo'], 172 gather_facts=False, 173 tasks=[ 174 {'include_role': 'name=l1'} 175 ] 176 ), loader=self.loader, variable_manager=self.var_manager) 177 178 tasks = play.compile() 179 expected_roles = ['l1', 'l2', 'l3'] 180 for role, task_vars in self.get_tasks_vars(play, tasks): 181 expected_roles.remove(role) 182 # Outer-most role must not have variables from inner roles yet 183 if role == 'l1': 184 self.assertEqual(task_vars.get('l1_variable'), 'l1-main') 185 self.assertEqual(task_vars.get('l2_variable'), None) 186 self.assertEqual(task_vars.get('l3_variable'), None) 187 self.assertEqual(task_vars.get('test_variable'), 'l1-main') 188 # Middle role must have variables from outer role, but not inner 189 elif role == 'l2': 190 self.assertEqual(task_vars.get('l1_variable'), 'l1-main') 191 self.assertEqual(task_vars.get('l2_variable'), 'l2-main') 192 self.assertEqual(task_vars.get('l3_variable'), None) 193 self.assertEqual(task_vars.get('test_variable'), 'l2-main') 194 # Inner role must have variables from both outer roles 195 elif role == 'l3': 196 self.assertEqual(task_vars.get('l1_variable'), 'l1-main') 197 self.assertEqual(task_vars.get('l2_variable'), 'l2-main') 198 self.assertEqual(task_vars.get('l3_variable'), 'l3-main') 199 self.assertEqual(task_vars.get('test_variable'), 'l3-main') 200 else: 201 self.fail() 202 self.assertFalse(expected_roles) 203 204 @patch('ansible.playbook.role.definition.unfrackpath', 205 mock_unfrackpath_noop) 206 def test_nested_alt_files(self): 207 208 """ 209 Test nested includes with alternative tasks and variables. 210 211 Variables from outer roles should be inherited, but overridden in inner 212 roles. 213 """ 214 215 play = Play.load(dict( 216 name="test play", 217 hosts=['foo'], 218 gather_facts=False, 219 tasks=[ 220 {'include_role': 'name=l1 tasks_from=alt defaults_from=alt'} 221 ] 222 ), loader=self.loader, variable_manager=self.var_manager) 223 224 tasks = play.compile() 225 expected_roles = ['l1', 'l2', 'l3'] 226 for role, task_vars in self.get_tasks_vars(play, tasks): 227 expected_roles.remove(role) 228 # Outer-most role must not have variables from inner roles yet 229 if role == 'l1': 230 self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') 231 self.assertEqual(task_vars.get('l2_variable'), None) 232 self.assertEqual(task_vars.get('l3_variable'), None) 233 self.assertEqual(task_vars.get('test_variable'), 'l1-alt') 234 # Middle role must have variables from outer role, but not inner 235 elif role == 'l2': 236 self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') 237 self.assertEqual(task_vars.get('l2_variable'), 'l2-alt') 238 self.assertEqual(task_vars.get('l3_variable'), None) 239 self.assertEqual(task_vars.get('test_variable'), 'l2-alt') 240 # Inner role must have variables from both outer roles 241 elif role == 'l3': 242 self.assertEqual(task_vars.get('l1_variable'), 'l1-alt') 243 self.assertEqual(task_vars.get('l2_variable'), 'l2-alt') 244 self.assertEqual(task_vars.get('l3_variable'), 'l3-alt') 245 self.assertEqual(task_vars.get('test_variable'), 'l3-alt') 246 else: 247 self.fail() 248 self.assertFalse(expected_roles) 249