482 lines
18 KiB
Python
482 lines
18 KiB
Python
# Copyright 2020 Red Hat, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
|
|
# @matbu backward compatibility for stable/train
|
|
try:
|
|
from pathlib import PosixPath
|
|
except ImportError:
|
|
from pathlib2 import PosixPath
|
|
|
|
from validations_libs import constants
|
|
|
|
VALIDATIONS_LIST = [{
|
|
'description': 'My Validation One Description',
|
|
'groups': ['prep', 'pre-deployment', 'no-op', 'post'],
|
|
'categories': ['os', 'system', 'ram'],
|
|
'products': ['product1'],
|
|
'id': 'my_val1',
|
|
'name': 'My Validation One Name',
|
|
'parameters': {}
|
|
}, {
|
|
'description': 'My Validation Two Description',
|
|
'groups': ['prep', 'pre-introspection', 'post', 'pre'],
|
|
'categories': ['networking'],
|
|
'products': ['product1'],
|
|
'id': 'my_val2',
|
|
'name': 'My Validation Two Name',
|
|
'parameters': {'min_value': 8}
|
|
}]
|
|
|
|
VALIDATIONS_LIST_GROUP = [{
|
|
'description': 'My Validation Two Description',
|
|
'groups': ['prep', 'pre-introspection'],
|
|
'categories': ['networking'],
|
|
'products': ['product1'],
|
|
'id': 'my_val2',
|
|
'name': 'My Validation Two Name',
|
|
'parameters': {'min_value': 8}
|
|
}]
|
|
|
|
|
|
VALIDATION_LIST_RESULT = (('ID', 'Name', 'Groups', 'Categories', 'Products'),
|
|
[('my_val2', 'My Validation Two Name',
|
|
['prep', 'pre-introspection'],
|
|
['networking'],
|
|
['product1'])])
|
|
|
|
GROUPS_LIST = [
|
|
'group1',
|
|
'group2',
|
|
'group3'
|
|
]
|
|
|
|
BAD_VALIDATIONS_LOGS_CONTENTS_LIST = [{
|
|
'plays': [{
|
|
'play': {
|
|
'duration': {
|
|
'end': '2019-11-25T13:40:17.538611Z',
|
|
},
|
|
'host': 'undercloud',
|
|
'id': '008886df-d297-1eaa-2a74-000000000008',
|
|
'validation_id': '512e',
|
|
'validation_path':
|
|
'/usr/share/openstack-tripleo-validations/playbooks'
|
|
}}],
|
|
'stats': {
|
|
'undercloud': {
|
|
'changed': 0,
|
|
'failures': 0,
|
|
'ignored': 0,
|
|
'ok': 0,
|
|
'rescued': 0,
|
|
'skipped': 0,
|
|
'unreachable': 1
|
|
}
|
|
},
|
|
'validation_output': []
|
|
}]
|
|
|
|
FAILED_VALIDATIONS_LOGS_CONTENTS_LIST = [{
|
|
'plays': [{
|
|
'play': {
|
|
'duration': {
|
|
'end': '2019-11-25T13:40:17.538611Z',
|
|
},
|
|
'host': 'undercloud',
|
|
'id': '008886df-d297-1eaa-2a74-000000000008',
|
|
'validation_id': '512e',
|
|
'validation_path':
|
|
'/usr/share/openstack-tripleo-validations/playbooks'
|
|
}}],
|
|
'stats': {
|
|
'undercloud': {
|
|
'changed': 0,
|
|
'failures': 1,
|
|
'ignored': 0,
|
|
'ok': 0,
|
|
'rescued': 0,
|
|
'skipped': 0,
|
|
'unreachable': 0
|
|
}
|
|
},
|
|
'validation_output': [
|
|
{
|
|
"task": {
|
|
"hosts": {
|
|
"localhost": {
|
|
"_ansible_no_log": False,
|
|
"action": "fail",
|
|
"changed": False,
|
|
"failed": True,
|
|
"failed_when_result": True,
|
|
"msg": "Fake Failed"
|
|
}
|
|
},
|
|
"name": "Verify Fake requirements",
|
|
"status": "FAILED"
|
|
}
|
|
}
|
|
]
|
|
}]
|
|
|
|
VALIDATIONS_LOGS_CONTENTS_LIST = [{
|
|
'plays': [{
|
|
'play': {
|
|
'duration': {
|
|
'end': '2019-11-25T13:40:17.538611Z',
|
|
'start': '2019-11-25T13:40:14.404623Z',
|
|
'time_elapsed': '0:00:03.753'
|
|
},
|
|
'host': 'undercloud',
|
|
'id': '008886df-d297-1eaa-2a74-000000000008',
|
|
'validation_id': '512e',
|
|
'validation_path':
|
|
'/usr/share/openstack-tripleo-validations/playbooks'
|
|
},
|
|
'tasks': [
|
|
{
|
|
'hosts': {
|
|
'undercloud': {
|
|
'_ansible_no_log': False,
|
|
'action': 'command',
|
|
'changed': False,
|
|
'cmd': [u'ls', '/sys/class/block/'],
|
|
'delta': '0:00:00.018913',
|
|
'end': '2019-11-25 13:40:17.120368',
|
|
'invocation': {
|
|
'module_args': {
|
|
'_raw_params': 'ls /sys/class/block/',
|
|
'_uses_shell': False,
|
|
'argv': None,
|
|
'chdir': None,
|
|
'creates': None,
|
|
'executable': None,
|
|
'removes': None,
|
|
'stdin': None,
|
|
'stdin_add_newline': True,
|
|
'strip_empty_ends': True,
|
|
'warn': True
|
|
}
|
|
},
|
|
'rc': 0,
|
|
'start': '2019-11-25 13:40:17.101455',
|
|
'stderr': '',
|
|
'stderr_lines': [],
|
|
'stdout': 'vda',
|
|
'stdout_lines': [u'vda']
|
|
}
|
|
},
|
|
'task': {
|
|
'duration': {
|
|
'end': '2019-11-25T13:40:17.336687Z',
|
|
'start': '2019-11-25T13:40:14.529880Z'
|
|
},
|
|
'id':
|
|
'008886df-d297-1eaa-2a74-00000000000d',
|
|
'name':
|
|
'advanced-format-512e-support : List the available drives'
|
|
}
|
|
},
|
|
{
|
|
'hosts': {
|
|
'undercloud': {
|
|
'action':
|
|
'advanced_format',
|
|
'changed': False,
|
|
'msg':
|
|
'All items completed',
|
|
'results': [{
|
|
'_ansible_item_label': 'vda',
|
|
'_ansible_no_log': False,
|
|
'ansible_loop_var': 'item',
|
|
'changed': False,
|
|
'item': 'vda',
|
|
'skip_reason': 'Conditional result was False',
|
|
'skipped': True
|
|
}],
|
|
'skipped': True
|
|
}
|
|
},
|
|
'task': {
|
|
'duration': {
|
|
'end': '2019-11-25T13:40:17.538611Z',
|
|
'start': '2019-11-25T13:40:17.341704Z'
|
|
},
|
|
'id': '008886df-d297-1eaa-2a74-00000000000e',
|
|
'name':
|
|
'advanced-format-512e-support: Detect the drive'
|
|
}
|
|
}
|
|
]
|
|
}],
|
|
'stats': {
|
|
'undercloud': {
|
|
'changed': 0,
|
|
'failures': 0,
|
|
'ignored': 0,
|
|
'ok': 1,
|
|
'rescued': 0,
|
|
'skipped': 1,
|
|
'unreachable': 0
|
|
}
|
|
},
|
|
'validation_output': [{'task': {
|
|
'hosts': {u'foo': {}},
|
|
'name': u'Check if iscsi.service is enabled',
|
|
'status': u'FAILED'}}]
|
|
}]
|
|
|
|
VALIDATIONS_DATA = {'Description': 'My Validation One Description',
|
|
'Groups': ['prep', 'pre-deployment'],
|
|
'categories': ['os', 'system', 'ram'],
|
|
'products': ['product1'],
|
|
'ID': 'my_val1',
|
|
'Name': 'My Validation One Name',
|
|
'parameters': {}}
|
|
|
|
VALIDATIONS_STATS = {'Last execution date': '2019-11-25 13:40:14',
|
|
'Number of execution': 'Total: 1, Passed: 0, Failed: 1'}
|
|
|
|
FAKE_WRONG_PLAYBOOK = [{
|
|
'hosts': 'undercloud',
|
|
'roles': ['advanced_format_512e_support'],
|
|
'vars': {
|
|
'nometadata': {
|
|
'description': 'foo',
|
|
'groups': ['prep', 'pre-deployment'],
|
|
'categories': ['os', 'storage'],
|
|
'products': ['product1'],
|
|
'name': 'Advanced Format 512e Support'
|
|
}
|
|
}
|
|
}]
|
|
|
|
FAKE_PLAYBOOK = [{'hosts': 'undercloud',
|
|
'roles': ['advanced_format_512e_support'],
|
|
'vars': {'metadata': {'description': 'foo',
|
|
'groups': ['prep', 'pre-deployment'],
|
|
'categories': ['os', 'storage'],
|
|
'products': ['product1'],
|
|
'name':
|
|
'Advanced Format 512e Support',
|
|
'path': '/tmp'}}}]
|
|
|
|
FAKE_PLAYBOOK2 = [{'hosts': 'undercloud',
|
|
'roles': ['advanced_format_512e_support'],
|
|
'vars': {'metadata': {'description': 'foo',
|
|
'groups': ['prep', 'pre-deployment'],
|
|
'categories': ['os', 'storage'],
|
|
'products': ['product1'],
|
|
'name':
|
|
'Advanced Format 512e Support'},
|
|
'foo': 'bar'}}]
|
|
|
|
FAKE_PLAYBOOK3 = [{'hosts': 'undercloud',
|
|
'roles': ['advanced_format_512e_support'],
|
|
'vars': {'metadata': {'description': 'foo',
|
|
'name':
|
|
'Advanced Format 512e Support'},
|
|
'foo': 'bar'}}]
|
|
|
|
FAKE_VARS = {'foo': 'bar'}
|
|
|
|
FAKE_METADATA = {'id': 'foo',
|
|
'description': 'foo',
|
|
'groups': ['prep', 'pre-deployment'],
|
|
'categories': ['os', 'storage'],
|
|
'products': ['product1'],
|
|
'name': 'Advanced Format 512e Support',
|
|
'path': '/tmp'}
|
|
|
|
FORMATED_DATA = {'Description': 'foo',
|
|
'Groups': ['prep', 'pre-deployment'],
|
|
'Categories': ['os', 'storage'],
|
|
'Products': ['product1'],
|
|
'ID': 'foo',
|
|
'Name': 'Advanced Format 512e Support',
|
|
'Path': '/tmp'}
|
|
|
|
GROUP = {'no-op': [{'description': 'noop-foo'}],
|
|
'pre': [{'description': 'pre-foo'}],
|
|
'post': [{'description': 'post-foo'}]}
|
|
|
|
FAKE_SUCCESS_RUN = [{'Duration': '0:00:01.761',
|
|
'Host_Group': 'overcloud',
|
|
'Status': 'PASSED',
|
|
'Status_by_Host': 'subnode-1,PASSED, subnode-2,PASSED',
|
|
'UUID': '123',
|
|
'Unreachable_Hosts': '',
|
|
'Validations': 'foo'}]
|
|
|
|
FAKE_FAILED_RUN = [{'Duration': '0:00:01.761',
|
|
'Host_Group': 'overcloud',
|
|
'Status': 'FAILED',
|
|
'Status_by_Host': 'subnode-1,FAILED, subnode-2,PASSED',
|
|
'UUID': '123',
|
|
'Unreachable_Hosts': '',
|
|
'Validations': 'foo'},
|
|
{'Duration': '0:00:01.761',
|
|
'Host_Group': 'overcloud',
|
|
'Status': 'FAILED',
|
|
'Status_by_Host': 'subnode-1,FAILED, subnode-2,PASSED',
|
|
'UUID': '123',
|
|
'Unreachable_Hosts': '',
|
|
'Validations': 'foo'},
|
|
{'Duration': '0:00:01.761',
|
|
'Host_Group': 'overcloud',
|
|
'Status': 'PASSED',
|
|
'Status_by_Host': 'subnode-1,PASSED, subnode-2,PASSED',
|
|
'UUID': '123',
|
|
'Unreachable_Hosts': '',
|
|
'Validations': 'foo'}]
|
|
|
|
FAKE_VALIDATIONS_PATH = '/usr/share/ansible/validation-playbooks'
|
|
|
|
DEFAULT_CONFIG = {'validation_dir': '/usr/share/ansible/validation-playbooks',
|
|
'enable_community_validations': True,
|
|
'ansible_base_dir': '/usr/share/ansible/',
|
|
'output_log': 'output.log',
|
|
'history_limit': 15,
|
|
'fit_width': True}
|
|
|
|
CONFIG_WITH_COMMUNITY_VAL_DISABLED = {
|
|
'validation_dir': '/usr/share/ansible/validation-playbooks',
|
|
'enable_community_validations': False,
|
|
'ansible_base_dir': '/usr/share/ansible/',
|
|
'output_log': 'output.log',
|
|
'history_limit': 15,
|
|
'fit_width': True}
|
|
|
|
WRONG_HISTORY_CONFIG = {'default': {'history_limit': 0}}
|
|
|
|
ANSIBLE_RUNNER_CONFIG = {'verbosity': 5,
|
|
'fact_cache_type': 'jsonfile',
|
|
'quiet': True, 'rotate_artifacts': 256}
|
|
|
|
ANSIBLE_ENVIRONNMENT_CONFIG = {'ANSIBLE_CALLBACK_WHITELIST':
|
|
'validation_stdout,validation_json,'
|
|
'profile_tasks',
|
|
'ANSIBLE_STDOUT_CALLBACK': 'validation_stdout'}
|
|
|
|
COVAL_SUBDIR = [PosixPath("/foo/bar/community-validations/roles"),
|
|
PosixPath("/foo/bar/community-validations/playbooks"),
|
|
PosixPath("/foo/bar/community-validations/library"),
|
|
PosixPath("/foo/bar/community-validations/lookup_plugins")]
|
|
|
|
COVAL_MISSING_SUBDIR = [PosixPath("/foo/bar/community-validations/roles"),
|
|
PosixPath("/foo/bar/community-validations/playbooks")]
|
|
|
|
FAKE_COVAL_ITERDIR1 = iter(COVAL_SUBDIR)
|
|
|
|
FAKE_COVAL_MISSING_SUBDIR_ITERDIR1 = iter(COVAL_MISSING_SUBDIR)
|
|
|
|
FAKE_ROLES_ITERDIR1 = iter([PosixPath("/u/s/a/roles/role_1"),
|
|
PosixPath("/u/s/a/roles/role_2"),
|
|
PosixPath("/u/s/a/roles/role_3"),
|
|
PosixPath("/u/s/a/roles/role_4"),
|
|
PosixPath("/u/s/a/roles/role_5"),
|
|
PosixPath("/u/s/a/roles/my_val")])
|
|
|
|
FAKE_ROLES_ITERDIR2 = iter([PosixPath("/u/s/a/roles/role_1"),
|
|
PosixPath("/u/s/a/roles/role_2"),
|
|
PosixPath("/u/s/a/roles/role_3"),
|
|
PosixPath("/u/s/a/roles/role_4"),
|
|
PosixPath("/u/s/a/roles/role_5"),
|
|
PosixPath("/u/s/a/roles/role_6")])
|
|
|
|
FAKE_PLAYBOOKS_ITERDIR1 = iter([PosixPath("/u/s/a/plays/play_1.yaml"),
|
|
PosixPath("/u/s/a/plays/play_2.yaml"),
|
|
PosixPath("/u/s/a/plays/play_3.yaml"),
|
|
PosixPath("/u/s/a/plays/play_4.yaml"),
|
|
PosixPath("/u/s/a/plays/play_5.yaml"),
|
|
PosixPath("/u/s/a/plays/my-val.yaml")])
|
|
|
|
FAKE_PLAYBOOKS_ITERDIR2 = iter([PosixPath("/u/s/a/plays/play_1.yaml"),
|
|
PosixPath("/u/s/a/plays/play_2.yaml"),
|
|
PosixPath("/u/s/a/plays/play_3.yaml"),
|
|
PosixPath("/u/s/a/plays/play_4.yaml"),
|
|
PosixPath("/u/s/a/plays/play_5.yaml"),
|
|
PosixPath("/u/s/a/plays/play_6.yaml")])
|
|
|
|
FAKE_PLAYBOOK_TEMPLATE = \
|
|
"""---
|
|
# This playbook has been generated by the `validation init` CLI.
|
|
#
|
|
# As shown here in this template, the validation playbook requires three
|
|
# top-level directive:
|
|
# ``hosts``, ``vars -> metadata`` and ``roles``.
|
|
#
|
|
# ``hosts``: specifies which nodes to run the validation on. The options can
|
|
# be ``all`` (run on all nodes), or you could use the hosts defined
|
|
# in the inventory.
|
|
# ``vars``: this section serves for storing variables that are going to be
|
|
# available to the Ansible playbook. The validations API uses the
|
|
# ``metadata`` section to read each validation's name and description
|
|
# These values are then reported by the API.
|
|
#
|
|
# The validations can be grouped together by specyfying a ``groups`` metadata.
|
|
# Groups function similar to tags and a validation can thus be part of many
|
|
# groups. To get a full list of the groups available and their description,
|
|
# please run the following command on your Ansible Controller host:
|
|
#
|
|
# $ validation show group
|
|
#
|
|
# The validations can also be categorized by technical domain and acan belong to
|
|
# one or multiple ``categories``. For example, if your validation checks some
|
|
# networking related configuration, you may want to put ``networking`` as a
|
|
# category. Note that this section is open and you are free to categorize your
|
|
# validations as you like.
|
|
#
|
|
# The ``products`` section refers to the product on which you would like to run
|
|
# the validation. It's another way to categorized your community validations.
|
|
# Note that, by default, ``community`` is set in the ``products`` section to
|
|
# help you list your validations by filtering by products:
|
|
#
|
|
# $ validation list --product community
|
|
#
|
|
- hosts: hostname
|
|
gather_facts: false
|
|
vars:
|
|
metadata:
|
|
name: Brief and general description of the validation
|
|
description: |
|
|
The complete description of this validation should be here
|
|
# GROUPS:
|
|
# Run ``validation show group`` to get the list of groups
|
|
# :type group: `list`
|
|
# If you don't want to add groups for your validation, just
|
|
# set an empty list to the groups key
|
|
groups: []
|
|
# CATEGORIES:
|
|
# :type group: `list`
|
|
# If you don't want to categorize your validation, just
|
|
# set an empty list to the categories key
|
|
categories: []
|
|
products:
|
|
- community
|
|
roles:
|
|
- my_val
|
|
"""
|
|
|
|
|
|
def fake_ansible_runner_run_return(status='successful', rc=0):
|
|
return status, rc
|
|
|
|
|
|
def _accept_default_log_path(path, *args):
|
|
if path == constants.VALIDATIONS_LOG_BASEDIR:
|
|
return True
|
|
return False
|