3 def lint(sls_yaml
, types
):
5 Check the sls_yaml for Salt errors / warnings
7 typedb : Nested dictionary of Salt states/functions/parameters (partial)
8 sls_yaml: ruamel.yaml[jinja2].load()'d output for some Salt state file.
10 Returns: (errors, warnings)
11 errors: List of (line#, error) tuples
12 warnings: List of (line#, warnings) tuples
15 pp
= pprint
.PrettyPrinter(indent
=4)
16 #pp.pprint(dir(sls_yaml))
17 #pp.pprint(sls_yaml.__dict__)
20 def lint_parameters(function_name
, parameters
, parameter_types
):
23 function_name: String of the form "<state_name>.<function>" currently being linted
24 parameters: Map of {paramter_name: parameter_data} items currently being linted
25 parameter_types: Map of {parameter_name: parameter_type} items
27 errors: List of error string
28 warnings: List of warning strings
32 for parameter
in parameters
:
33 parameter_name
= next(iter(parameter
.keys()))
35 ## parameter is either just a string or a {'parameter' : data} map, or always a map ?
37 if parameter_name
in types
['globals']:
39 elif parameter_name
not in parameter_types
:
40 s_warning
= "Unexpected parameter name {} for {}"
41 warnings
.append((parameter
.lc
.line
+ 1, s_warning
.format(parameter_name
, function_name
)))
43 ## TODO: Add that parameter.values()[0] matches the against parameter_types[parameter] type
45 return (errors
, warnings
)
48 def lint_function(state_name
, function_calls
, function_types
):
51 state_name: String of the state_name currently being linted
52 function_calls: Map of {function_name: parameters} items currently being linteds
53 function_types; Map of {function_name: parameter_types} items
55 errors: List of error string
56 warnings: List of warning strings
60 for function_name
, parameters
in function_calls
.items():
61 if function_name
not in function_types
:
62 warnings
.append((parameters
.lc
.line
+1, "Unexpected function name {}.{}.".format(state_name
, function_name
)))
65 (parameter_errors
, parameter_warnings
) = lint_parameters(state_name
+ "." + function_name
, parameters
, function_types
[function_name
])
66 errors
+= parameter_errors
67 warnings
+= parameter_warnings
68 return (errors
, warnings
)
70 ## ------------------------------
72 state_types
= types
['states']
76 for label
, label_value
in sls_yaml
.items():
78 # It's possible the label_value is just a 'state.function'. See example_sls/two-items.sls
79 if not isinstance(label_value
, dict):
80 value
= {label_value
: []}
84 for state_function_name
, function_calls_or_parameters
in value
.items():
86 # state_function_name should be 'state_name' or 'state_name.function_name'
87 # sosf => 'state or state.function'
88 # = [state_name] or [state_name, function_name]
89 sosf
= state_function_name
.split('.')
91 # Verify that sosf[0] is an expected state:
93 if sosf
[0] not in state_types
:
94 warnings
.append((value
.lc
.line
+ 1, "Unexpected state name {}.".format(sosf
[0])))
100 # function_calls_or_parameters[0] will be the function name
101 # function_call_or_parameters[1:] will be the parameters
104 if not function_calls_or_parameters
:
105 errors
.append(label_value
.lc
.line
+ 1, "Missing function name in parameter list for state {}.".format(state_name
))
108 function_name
= function_calls_or_parameters
[0]
109 if function_name
not in state_types
[state_name
]:
110 warnings
.append((state_function_name
.lc
.line
+ 1, "Unexpected function name {} for {}.".format(function_name
, state_name
)))
112 parameters
= function_call_or_parameters
[1:]
113 (function_errors
, function_warnings
) = lint_function(state_name
+ "." + function_name
, parameters
, state_types
[state_name
][function_name
])
114 errors
+= function_errors
115 warnings
+= function_warnings
117 # "state.function" case
118 # function_calls_or_parameters will be a list of parameters
120 function_name
= sosf
[1]
121 if function_name
not in state_types
[state_name
]:
123 # TODO: This gives the line number at the top of the label block which isn't great.
124 # It would be better to give the exact like number of the invalid function
125 warnings
.append((sls_yaml
.lc
.key(label
)[0] + 1, "Unexpected function name {} for {}.".format(function_name
, state_name
)))
128 # Children should be parameters of "state.function"
129 (parameter_errors
, parameter_warnings
) = lint_parameters(state_name
+ "." + function_name
, function_calls_or_parameters
, state_types
[state_name
][function_name
])
130 errors
+= parameter_errors
131 warnings
+= parameter_warnings
133 # Anything other than "state" or "state.function" is an error.
135 errors
.append((value
.lc
.line
+ 1, "Expected <state> or <state>.<function>: Too many '.'s in {}".format(state_function_name
)))
138 return(errors
, warnings
)