This patch add a custom ansible-lint rule to enforce the structure of the validations playbooks: *ValidationHasMetadataRule*: Throw an ansible-lint error if: - the *hosts* key is empty or not found, - *vars* dictionary is missing, - *metadata* dict is missing in *vars* - *name*/*description*/*groups* keys are missing or found with a wrong data type - the validation belongs to one or several groups NOT in the official list of groups (groups.yaml) *YAMLLINT*: - Enable yamllint check in tox linters - WIP Fix detected yamllint errors Change-Id: If233286aa9f4299f02f13dc34f1e8c05d89df851 Signed-off-by: Gael Chamoulaud <gchamoul@redhat.com>changes/16/700016/5
parent
bf65faa2c3
commit
e50e1a067d
@ -0,0 +1,138 @@
|
||||
import os
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from ansiblelint import AnsibleLintRule
|
||||
|
||||
|
||||
class ValidationHasMetadataRule(AnsibleLintRule):
|
||||
id = '750'
|
||||
shortdesc = 'Validation playbook must have mandatory metadata'
|
||||
|
||||
info = """
|
||||
---
|
||||
- hosts: localhost
|
||||
vars:
|
||||
metadata:
|
||||
name: Validation Name
|
||||
description: >
|
||||
A full description of the validation.
|
||||
groups:
|
||||
- group1
|
||||
- group2
|
||||
- group3
|
||||
"""
|
||||
|
||||
description = (
|
||||
"The Validation playbook must have mandatory metadata:\n"
|
||||
"```{}```".format(info)
|
||||
)
|
||||
|
||||
severity = 'HIGH'
|
||||
tags = ['metadata']
|
||||
|
||||
no_vars_found = "The validation playbook must contain a 'vars' dictionary"
|
||||
no_meta_found = (
|
||||
"The validation playbook must contain "
|
||||
"a 'metadata' dictionary under vars"
|
||||
)
|
||||
no_groups_found = \
|
||||
"*metadata* should contain a list of group (groups)"
|
||||
|
||||
unknown_groups_found = (
|
||||
"Unkown group(s) '{}' found! "
|
||||
"The official list of groups are '{}'. "
|
||||
"To add a new validation group, please add it in the groups.yaml "
|
||||
"file at the root of the tripleo-validations project."
|
||||
)
|
||||
|
||||
def get_groups(self):
|
||||
"""Returns a list of group names supported by
|
||||
tripleo-validations by reading 'groups.yaml'
|
||||
file located in the base direcotry.
|
||||
"""
|
||||
results = []
|
||||
|
||||
grp_file_path = os.path.abspath('groups.yaml')
|
||||
|
||||
with open(grp_file_path, "r") as grps:
|
||||
contents = yaml.safe_load(grps)
|
||||
|
||||
for grp_name, grp_desc in sorted(contents.items()):
|
||||
results.append(grp_name)
|
||||
|
||||
return results
|
||||
|
||||
def matchplay(self, file, data):
|
||||
results = []
|
||||
path = file['path']
|
||||
|
||||
if file['type'] == 'playbook':
|
||||
if path.startswith("playbooks/") or \
|
||||
path.find("tripleo-validations/playbooks/") > 0:
|
||||
|
||||
# *hosts* line check
|
||||
hosts = data.get('hosts', None)
|
||||
if not hosts:
|
||||
return [({
|
||||
path: data
|
||||
}, "No *hosts* key found in the playbook")]
|
||||
|
||||
# *vars* lines check
|
||||
vars = data.get('vars', None)
|
||||
if not vars:
|
||||
return [({
|
||||
path: data
|
||||
}, self.no_vars_found)]
|
||||
else:
|
||||
if not isinstance(vars, dict):
|
||||
return [({path: data}, '*vars* should be a dictionary')]
|
||||
|
||||
# *metadata* lines check
|
||||
metadata = data['vars'].get('metadata', None)
|
||||
if metadata:
|
||||
if not isinstance(metadata, dict):
|
||||
return [(
|
||||
{path: data},
|
||||
'*metadata* should be a dictionary')]
|
||||
else:
|
||||
return [({path: data}, self.no_meta_found)]
|
||||
|
||||
# *metadata>[name|description] lines check
|
||||
for info in ['name', 'description']:
|
||||
if not metadata.get(info, None):
|
||||
results.append((
|
||||
{path: data},
|
||||
'*metadata* should contain a %s key' % info))
|
||||
continue
|
||||
if not isinstance(metadata.get(info),
|
||||
six.string_types):
|
||||
results.append((
|
||||
{path: data},
|
||||
'*%s* should be a string' % info))
|
||||
|
||||
# *metadata>groups* lines check
|
||||
if not metadata.get('groups', None):
|
||||
results.append((
|
||||
{path: data},
|
||||
self.no_groups_found))
|
||||
else:
|
||||
if not isinstance(metadata.get('groups'), list):
|
||||
results.append((
|
||||
{path: data},
|
||||
'*groups* should be a list'))
|
||||
else:
|
||||
groups = metadata.get('groups')
|
||||
group_list = self.get_groups()
|
||||
unknown_groups_list = list(
|
||||
set(groups) - set(group_list))
|
||||
if unknown_groups_list:
|
||||
results.append((
|
||||
{path: data},
|
||||
self.unknown_groups_found.format(
|
||||
unknown_groups_list,
|
||||
group_list)
|
||||
))
|
||||
return results
|
||||
|
||||
return results
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
line-length:
|
||||
# matches hardcoded 160 value from ansible-lint
|
||||
max: 160
|
||||
|
||||
ignore: |
|
||||
zuul.d/*.yaml
|
||||
releasenotes/notes/*.yaml
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
- name: Ensure DNS resolution works
|
||||
command: "getent hosts {{ server_to_lookup }}"
|
||||
changed_when: False
|
||||
changed_when: false
|
||||
|
@ -1,26 +1,26 @@
|
||||
---
|
||||
- name: Get if chrony is enabled
|
||||
become: True
|
||||
become: true
|
||||
hiera:
|
||||
name: "chrony_enabled"
|
||||
|
||||
- when: chrony_enabled|bool
|
||||
block:
|
||||
- name: Populate service facts
|
||||