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
|
# Copyright (c) 2020, Joachim Lusiardi
# Copyright (c) 2020, Ansible Project
import os.path
import ansible.parsing.yaml.objects
from ansiblelint.rules import AnsibleLintRule
class IncludeMissingFileRule(AnsibleLintRule):
id = '505'
shortdesc = 'referenced files must exist'
description = (
'All files referenced by by include / import tasks '
'must exist. The check excludes files with jinja2 '
'templates in the filename.'
)
severity = 'MEDIUM'
tags = ['task', 'bug']
version_added = 'v4.3.0'
def matchplay(self, file, data):
absolute_directory = file.get('absolute_directory', None)
results = []
# avoid failing with a playbook having tasks: null
for task in (data.get('tasks', []) or []):
# ignore None tasks or
# if the id of the current rule is not in list of skipped rules for this play
if not task or self.id in task.get('skipped_rules', ()):
continue
# collect information which file was referenced for include / import
referenced_file = None
for key, val in task.items():
if not (key.startswith('include_') or
key.startswith('import_') or
key == 'include'):
continue
if isinstance(val, ansible.parsing.yaml.objects.AnsibleMapping):
referenced_file = val.get('file', None)
else:
referenced_file = val
# take the file and skip the remaining keys
if referenced_file:
break
if referenced_file is None or absolute_directory is None:
continue
# make sure we have a absolute path here and check if it is a file
referenced_file = os.path.join(absolute_directory, referenced_file)
# skip if this is a jinja2 templated reference
if '{{' in referenced_file:
continue
# existing files do not produce any error
if os.path.isfile(referenced_file):
continue
results.append(({'referenced_file': referenced_file},
'referenced missing file in %s:%i'
% (task['__file__'], task['__line__'])))
return results
|