Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> 

# 

# This file is part of Ansible 

# 

# Ansible is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# Ansible is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

# GNU General Public License for more details. 

# 

# You should have received a copy of the GNU General Public License 

# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 

 

from __future__ import (absolute_import, division, print_function) 

__metaclass__ = type 

 

import os 

 

from ansible import constants as C 

from ansible.errors import AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound, AnsibleAssertionError 

from ansible.module_utils.six import string_types 

 

try: 

from __main__ import display 

except ImportError: 

from ansible.utils.display import Display 

display = Display() 

 

 

def load_list_of_blocks(ds, play, parent_block=None, role=None, task_include=None, use_handlers=False, variable_manager=None, loader=None): 

''' 

Given a list of mixed task/block data (parsed from YAML), 

return a list of Block() objects, where implicit blocks 

are created for each bare Task. 

''' 

 

# we import here to prevent a circular dependency with imports 

from ansible.playbook.block import Block 

from ansible.playbook.task_include import TaskInclude 

from ansible.playbook.role_include import IncludeRole 

 

46 ↛ 47line 46 didn't jump to line 47, because the condition on line 46 was never true if not isinstance(ds, (list, type(None))): 

raise AnsibleAssertionError('%s should be a list or None but is %s' % (ds, type(ds))) 

 

block_list = [] 

50 ↛ 84line 50 didn't jump to line 84, because the condition on line 50 was never false if ds: 

count = iter(range(len(ds))) 

for i in count: 

block_ds = ds[i] 

# Implicit blocks are created by bare tasks listed in a play without 

# an explicit block statement. If we have two implicit blocks in a row, 

# squash them down to a single block to save processing time later. 

implicit_blocks = [] 

while block_ds is not None and not Block.is_block(block_ds): 

implicit_blocks.append(block_ds) 

i += 1 

# Advance the iterator, so we don't repeat 

next(count, None) 

try: 

block_ds = ds[i] 

except IndexError: 

block_ds = None 

 

# Loop both implicit blocks and block_ds as block_ds is the next in the list 

for b in (implicit_blocks, block_ds): 

if b: 

block_list.append( 

Block.load( 

b, 

play=play, 

parent_block=parent_block, 

role=role, 

task_include=task_include, 

use_handlers=use_handlers, 

variable_manager=variable_manager, 

loader=loader, 

) 

) 

 

return block_list 

 

 

def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_handlers=False, variable_manager=None, loader=None): 

''' 

Given a list of task datastructures (parsed from YAML), 

return a list of Task() or TaskInclude() objects. 

''' 

 

# we import here to prevent a circular dependency with imports 

from ansible.playbook.block import Block 

from ansible.playbook.handler import Handler 

from ansible.playbook.task import Task 

from ansible.playbook.task_include import TaskInclude 

from ansible.playbook.role_include import IncludeRole 

from ansible.playbook.handler_task_include import HandlerTaskInclude 

from ansible.template import Templar 

 

102 ↛ 103line 102 didn't jump to line 103, because the condition on line 102 was never true if not isinstance(ds, list): 

raise AnsibleAssertionError('The ds (%s) should be a list but was a %s' % (ds, type(ds))) 

 

task_list = [] 

for task_ds in ds: 

107 ↛ 108line 107 didn't jump to line 108, because the condition on line 107 was never true if not isinstance(task_ds, dict): 

AnsibleAssertionError('The ds (%s) should be a dict but was a %s' % (ds, type(ds))) 

 

110 ↛ 111line 110 didn't jump to line 111, because the condition on line 110 was never true if 'block' in task_ds: 

t = Block.load( 

task_ds, 

play=play, 

parent_block=block, 

role=role, 

task_include=task_include, 

use_handlers=use_handlers, 

variable_manager=variable_manager, 

loader=loader, 

) 

task_list.append(t) 

else: 

if 'include' in task_ds or 'import_tasks' in task_ds or 'include_tasks' in task_ds: 

 

125 ↛ 126line 125 didn't jump to line 126, because the condition on line 125 was never true if use_handlers: 

include_class = HandlerTaskInclude 

else: 

include_class = TaskInclude 

 

t = include_class.load( 

task_ds, 

block=block, 

role=role, 

task_include=None, 

variable_manager=variable_manager, 

loader=loader 

) 

 

all_vars = variable_manager.get_vars(play=play, task=t) 

templar = Templar(loader=loader, variables=all_vars) 

 

# check to see if this include is dynamic or static: 

# 1. the user has set the 'static' option to false or true 

# 2. one of the appropriate config options was set 

145 ↛ 146line 145 didn't jump to line 146, because the condition on line 145 was never true if 'include_tasks' in task_ds: 

is_static = False 

147 ↛ 148line 147 didn't jump to line 148, because the condition on line 147 was never true elif 'import_tasks' in task_ds: 

is_static = True 

149 ↛ 150line 149 didn't jump to line 150, because the condition on line 149 was never true elif t.static is not None: 

display.deprecated("The use of 'static' has been deprecated. " 

"Use 'import_tasks' for static inclusion, or 'include_tasks' for dynamic inclusion") 

is_static = t.static 

else: 

is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \ 

(use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \ 

(not templar._contains_vars(t.args['_raw_params']) and t.all_parents_static() and not t.loop) 

 

if is_static: 

159 ↛ 160line 159 didn't jump to line 160, because the condition on line 159 was never true if t.loop is not None: 

if 'import_tasks' in task_ds: 

raise AnsibleParserError("You cannot use loops on 'import_tasks' statements. You should use 'include_tasks' instead.", obj=task_ds) 

else: 

raise AnsibleParserError("You cannot use 'static' on an include with a loop", obj=task_ds) 

 

# we set a flag to indicate this include was static 

t.statically_loaded = True 

 

# handle relative includes by walking up the list of parent include 

# tasks and checking the relative result to see if it exists 

parent_include = block 

cumulative_path = None 

 

found = False 

subdir = 'tasks' 

175 ↛ 176line 175 didn't jump to line 176, because the condition on line 175 was never true if use_handlers: 

subdir = 'handlers' 

while parent_include is not None: 

178 ↛ 181line 178 didn't jump to line 181, because the condition on line 178 was never false if not isinstance(parent_include, TaskInclude): 

parent_include = parent_include._parent 

continue 

parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params'))) 

if cumulative_path is None: 

cumulative_path = parent_include_dir 

elif not os.path.isabs(cumulative_path): 

cumulative_path = os.path.join(parent_include_dir, cumulative_path) 

include_target = templar.template(t.args['_raw_params']) 

if t._role: 

new_basedir = os.path.join(t._role._role_path, subdir, cumulative_path) 

include_file = loader.path_dwim_relative(new_basedir, subdir, include_target) 

else: 

include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target) 

 

if os.path.exists(include_file): 

found = True 

break 

else: 

parent_include = parent_include._parent 

 

199 ↛ 216line 199 didn't jump to line 216, because the condition on line 199 was never false if not found: 

try: 

include_target = templar.template(t.args['_raw_params']) 

except AnsibleUndefinedVariable as e: 

raise AnsibleParserError( 

"Error when evaluating variable in include name: %s.\n\n" 

"When using static includes, ensure that any variables used in their names are defined in vars/vars_files\n" 

"or extra-vars passed in from the command line. Static includes cannot use variables from inventory\n" 

"sources like group or host vars." % t.args['_raw_params'], 

obj=task_ds, 

suppress_extended_error=True, 

orig_exc=e) 

211 ↛ 214line 211 didn't jump to line 214, because the condition on line 211 was never false if t._role: 

include_file = loader.path_dwim_relative(t._role._role_path, subdir, include_target) 

else: 

include_file = loader.path_dwim(include_target) 

 

try: 

data = loader.load_from_file(include_file) 

218 ↛ 219line 218 didn't jump to line 219, because the condition on line 218 was never true if data is None: 

display.warning('file %s is empty and had no tasks to include' % include_file) 

continue 

221 ↛ 222line 221 didn't jump to line 222, because the condition on line 221 was never true elif not isinstance(data, list): 

raise AnsibleParserError("included task files must contain a list of tasks", obj=data) 

 

# since we can't send callbacks here, we display a message directly in 

# the same fashion used by the on_include callback. We also do it here, 

# because the recursive nature of helper methods means we may be loading 

# nested includes, and we want the include order printed correctly 

display.vv("statically imported: %s" % include_file) 

except AnsibleFileNotFound: 

if t.static or \ 

C.DEFAULT_TASK_INCLUDES_STATIC or \ 

C.DEFAULT_HANDLER_INCLUDES_STATIC and use_handlers: 

raise 

display.deprecated( 

"Included file '%s' not found, however since this include is not " 

"explicitly marked as 'static: yes', we will try and include it dynamically " 

"later. In the future, this will be an error unless 'static: no' is used " 

"on the include task. If you do not want missing includes to be considered " 

"dynamic, use 'static: yes' on the include or set the global ansible.cfg " 

"options to make all includes static for tasks and/or handlers" % include_file, version="2.7" 

) 

task_list.append(t) 

continue 

 

ti_copy = t.copy(exclude_parent=True) 

ti_copy._parent = block 

included_blocks = load_list_of_blocks( 

data, 

play=play, 

parent_block=None, 

task_include=ti_copy, 

role=role, 

use_handlers=use_handlers, 

loader=loader, 

variable_manager=variable_manager, 

) 

 

# FIXME: remove once 'include' is removed 

# pop tags out of the include args, if they were specified there, and assign 

# them to the include. If the include already had tags specified, we raise an 

# error so that users know not to specify them both ways 

tags = ti_copy.vars.pop('tags', []) 

263 ↛ 264line 263 didn't jump to line 264, because the condition on line 263 was never true if isinstance(tags, string_types): 

tags = tags.split(',') 

 

266 ↛ 267line 266 didn't jump to line 267, because the condition on line 266 was never true if len(tags) > 0: 

if 'include_tasks' in task_ds or 'import_tasks' in task_ds: 

raise AnsibleParserError('You cannot specify "tags" inline to the task, it is a task keyword') 

if len(ti_copy.tags) > 0: 

raise AnsibleParserError( 

"Include tasks should not specify tags in more than one way (both via args and directly on the task). " 

"Mixing styles in which tags are specified is prohibited for whole import hierarchy, not only for single import statement", 

obj=task_ds, 

suppress_extended_error=True, 

) 

display.deprecated("You should not specify tags in the include parameters. All tags should be specified using the task-level option", 

version="2.7") 

else: 

tags = ti_copy.tags[:] 

 

# now we extend the tags on each of the included blocks 

for b in included_blocks: 

b.tags = list(set(b.tags).union(tags)) 

# END FIXME 

 

# FIXME: handlers shouldn't need this special handling, but do 

# right now because they don't iterate blocks correctly 

288 ↛ 289line 288 didn't jump to line 289, because the condition on line 288 was never true if use_handlers: 

for b in included_blocks: 

task_list.extend(b.block) 

else: 

task_list.extend(included_blocks) 

else: 

t.is_static = False 

task_list.append(t) 

 

297 ↛ 298line 297 didn't jump to line 298, because the condition on line 297 was never true elif 'include_role' in task_ds or 'import_role' in task_ds: 

ir = IncludeRole.load( 

task_ds, 

block=block, 

role=role, 

task_include=None, 

variable_manager=variable_manager, 

loader=loader, 

) 

 

# 1. the user has set the 'static' option to false or true 

# 2. one of the appropriate config options was set 

is_static = False 

if 'import_role' in task_ds: 

is_static = True 

 

elif ir.static is not None: 

display.deprecated("The use of 'static' for 'include_role' has been deprecated. " 

"Use 'import_role' for static inclusion, or 'include_role' for dynamic inclusion") 

is_static = ir.static 

 

if is_static: 

if ir.loop is not None: 

if 'import_tasks' in task_ds: 

raise AnsibleParserError("You cannot use loops on 'import_role' statements. You should use 'include_role' instead.", obj=task_ds) 

else: 

raise AnsibleParserError("You cannot use 'static' on an include_role with a loop", obj=task_ds) 

 

# we set a flag to indicate this include was static 

ir.statically_loaded = True 

 

# template the role name now, if needed 

all_vars = variable_manager.get_vars(play=play, task=ir) 

templar = Templar(loader=loader, variables=all_vars) 

if templar._contains_vars(ir._role_name): 

ir._role_name = templar.template(ir._role_name) 

 

# uses compiled list from object 

blocks, _ = ir.get_block_list(variable_manager=variable_manager, loader=loader) 

t = task_list.extend(blocks) 

else: 

# passes task object itself for latter generation of list 

t = task_list.append(ir) 

else: 

341 ↛ 342line 341 didn't jump to line 342, because the condition on line 341 was never true if use_handlers: 

t = Handler.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) 

else: 

t = Task.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) 

 

task_list.append(t) 

 

return task_list 

 

 

def load_list_of_roles(ds, play, current_role_path=None, variable_manager=None, loader=None): 

''' 

Loads and returns a list of RoleInclude objects from the datastructure 

list of role definitions 

''' 

 

# we import here to prevent a circular dependency with imports 

from ansible.playbook.role.include import RoleInclude 

 

360 ↛ 361line 360 didn't jump to line 361, because the condition on line 360 was never true if not isinstance(ds, list): 

raise AnsibleAssertionError('ds (%s) should be a list but was a %s' % (ds, type(ds))) 

 

roles = [] 

for role_def in ds: 

i = RoleInclude.load(role_def, play=play, current_role_path=current_role_path, variable_manager=variable_manager, loader=loader) 

roles.append(i) 

 

return roles