From eb35089c1c6b0b1a396807f00ded9a782a664b2f Mon Sep 17 00:00:00 2001 From: "Gael Chamoulaud (Strider)" Date: Wed, 4 Mar 2020 16:22:45 +0100 Subject: [PATCH] Add common Ansible roles and libraries Signed-off-by: Gael Chamoulaud (Strider) --- library/haproxy_conf.py | 89 ++++++++++ library/hiera.py | 64 +++++++ library/validations_read_ini.py | 166 ++++++++++++++++++ library/warn.py | 55 ++++++ .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 47 +++++ .../molecule/default/playbook.yml | 26 +++ .../tasks/main.yml | 10 ++ .../vars/main.yml | 9 + .../defaults/main.yml | 10 ++ .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 47 +++++ .../molecule/default/playbook.yml | 51 ++++++ .../molecule/default/prepare.yml | 25 +++ .../tasks/main.yml | 16 ++ .../vars/main.yml | 8 + roles/dns/defaults/main.yml | 2 + roles/dns/molecule/default/Dockerfile.j2 | 37 ++++ roles/dns/molecule/default/molecule.yml | 46 +++++ roles/dns/molecule/default/playbook.yml | 47 +++++ roles/dns/tasks/main.yml | 4 + roles/dns/vars/main.yml | 7 + roles/haproxy/README.md | 42 +++++ roles/haproxy/defaults/main.yml | 8 + roles/haproxy/molecule/default/Dockerfile.j2 | 36 ++++ roles/haproxy/molecule/default/molecule.yml | 47 +++++ roles/haproxy/molecule/default/playbook.yml | 71 ++++++++ roles/haproxy/tasks/main.yml | 51 ++++++ roles/haproxy/vars/main.yml | 6 + roles/no_op/tasks/main.yml | 4 + roles/no_op/vars/main.yml | 8 + roles/ntp/molecule/default/Dockerfile.j2 | 37 ++++ roles/ntp/molecule/default/molecule.yml | 47 +++++ roles/ntp/molecule/default/playbook.yml | 26 +++ roles/ntp/tasks/main.yml | 26 +++ roles/ntp/vars/main.yml | 10 ++ roles/service_status/defaults/main.yaml | 2 + .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 49 ++++++ .../molecule/default/playbook.yml | 25 +++ .../molecule/docker/Dockerfile.j2 | 37 ++++ .../molecule/docker/molecule.yml | 61 +++++++ .../molecule/docker/playbook.yml | 59 +++++++ .../molecule/docker/prepare.yml | 65 +++++++ .../molecule/podman/Dockerfile.j2 | 37 ++++ .../molecule/podman/bolt_state.db | Bin 0 -> 131072 bytes .../molecule/podman/molecule.yml | 49 ++++++ .../molecule/podman/playbook.yml | 46 +++++ .../molecule/podman/prepare.yml | 39 ++++ .../molecule/systemd/Dockerfile.j2 | 37 ++++ .../molecule/systemd/molecule.yml | 49 ++++++ .../molecule/systemd/playbook.yml | 44 +++++ .../molecule/systemd/prepare.yml | 39 ++++ roles/service_status/tasks/containers.yaml | 59 +++++++ roles/service_status/tasks/main.yaml | 3 + roles/service_status/tasks/systemd.yaml | 13 ++ .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 46 +++++ .../molecule/default/playbook.yml | 56 ++++++ .../molecule/default/prepare.yml | 30 ++++ roles/stonith_exists/tasks/main.yml | 22 +++ roles/stonith_exists/vars/main.yml | 11 ++ roles/undercloud_cpu/README.md | 36 ++++ roles/undercloud_cpu/defaults/main.yml | 3 + .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 46 +++++ .../molecule/default/playbook.yml | 42 +++++ roles/undercloud_cpu/tasks/main.yml | 7 + roles/undercloud_cpu/vars/main.yaml | 10 ++ roles/undercloud_disk_space/README.md | 36 ++++ roles/undercloud_disk_space/defaults/main.yml | 8 + .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 46 +++++ .../molecule/default/playbook.yml | 44 +++++ roles/undercloud_disk_space/tasks/main.yml | 39 ++++ roles/undercloud_disk_space/vars/main.yaml | 11 ++ roles/undercloud_ram/README.md | 36 ++++ roles/undercloud_ram/defaults/main.yml | 3 + .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 46 +++++ .../molecule/default/playbook.yml | 42 +++++ roles/undercloud_ram/tasks/main.yml | 9 + roles/undercloud_ram/vars/main.yaml | 11 ++ roles/undercloud_selinux_mode/README.md | 37 ++++ .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 47 +++++ .../molecule/default/playbook.yml | 26 +++ roles/undercloud_selinux_mode/tasks/main.yml | 24 +++ roles/undercloud_selinux_mode/vars/main.yml | 8 + roles/undercloud_service_status/README.md | 38 ++++ .../defaults/main.yml | 8 + .../undercloud_service_status/tasks/main.yml | 18 ++ .../undercloud_service_status/vars/main.yaml | 8 + roles/validate_selinux/defaults/main.yml | 27 +++ roles/validate_selinux/handlers/main.yml | 15 ++ .../molecule/default/Dockerfile | 37 ++++ .../molecule/default/molecule.yml | 49 ++++++ .../molecule/default/playbook.yml | 63 +++++++ .../molecule/default/prepare.yml | 60 +++++++ .../molecule/default/verify.yml | 15 ++ roles/validate_selinux/tasks/main.yml | 123 +++++++++++++ roles/validate_selinux/templates/skip-list.j2 | 3 + roles/validate_selinux/vars/main.yml | 22 +++ .../molecule/default/Dockerfile.j2 | 37 ++++ .../molecule/default/molecule.yml | 48 +++++ .../molecule/default/playbook.yml | 21 +++ .../molecule/default/prepare.yml | 60 +++++++ .../molecule/default/verify.yml | 15 ++ roles/xfs_check_ftype/tasks/main.yml | 25 +++ roles/xfs_check_ftype/vars/main.yml | 8 + .../library/test_validations_read_ini.py | 144 +++++++++++++++ 111 files changed, 3820 insertions(+) create mode 100644 library/haproxy_conf.py create mode 100644 library/hiera.py create mode 100644 library/validations_read_ini.py create mode 100644 library/warn.py create mode 100644 roles/advanced_format_512e_support/molecule/default/Dockerfile.j2 create mode 100644 roles/advanced_format_512e_support/molecule/default/molecule.yml create mode 100644 roles/advanced_format_512e_support/molecule/default/playbook.yml create mode 100644 roles/advanced_format_512e_support/tasks/main.yml create mode 100644 roles/advanced_format_512e_support/vars/main.yml create mode 100644 roles/check_latest_packages_version/defaults/main.yml create mode 100644 roles/check_latest_packages_version/molecule/default/Dockerfile.j2 create mode 100644 roles/check_latest_packages_version/molecule/default/molecule.yml create mode 100644 roles/check_latest_packages_version/molecule/default/playbook.yml create mode 100644 roles/check_latest_packages_version/molecule/default/prepare.yml create mode 100644 roles/check_latest_packages_version/tasks/main.yml create mode 100644 roles/check_latest_packages_version/vars/main.yml create mode 100644 roles/dns/defaults/main.yml create mode 100644 roles/dns/molecule/default/Dockerfile.j2 create mode 100644 roles/dns/molecule/default/molecule.yml create mode 100644 roles/dns/molecule/default/playbook.yml create mode 100644 roles/dns/tasks/main.yml create mode 100644 roles/dns/vars/main.yml create mode 100644 roles/haproxy/README.md create mode 100644 roles/haproxy/defaults/main.yml create mode 100644 roles/haproxy/molecule/default/Dockerfile.j2 create mode 100644 roles/haproxy/molecule/default/molecule.yml create mode 100644 roles/haproxy/molecule/default/playbook.yml create mode 100644 roles/haproxy/tasks/main.yml create mode 100644 roles/haproxy/vars/main.yml create mode 100644 roles/no_op/tasks/main.yml create mode 100644 roles/no_op/vars/main.yml create mode 100644 roles/ntp/molecule/default/Dockerfile.j2 create mode 100644 roles/ntp/molecule/default/molecule.yml create mode 100644 roles/ntp/molecule/default/playbook.yml create mode 100644 roles/ntp/tasks/main.yml create mode 100644 roles/ntp/vars/main.yml create mode 100644 roles/service_status/defaults/main.yaml create mode 100644 roles/service_status/molecule/default/Dockerfile.j2 create mode 100644 roles/service_status/molecule/default/molecule.yml create mode 100644 roles/service_status/molecule/default/playbook.yml create mode 100644 roles/service_status/molecule/docker/Dockerfile.j2 create mode 100644 roles/service_status/molecule/docker/molecule.yml create mode 100644 roles/service_status/molecule/docker/playbook.yml create mode 100644 roles/service_status/molecule/docker/prepare.yml create mode 100644 roles/service_status/molecule/podman/Dockerfile.j2 create mode 100644 roles/service_status/molecule/podman/bolt_state.db create mode 100644 roles/service_status/molecule/podman/molecule.yml create mode 100644 roles/service_status/molecule/podman/playbook.yml create mode 100644 roles/service_status/molecule/podman/prepare.yml create mode 100644 roles/service_status/molecule/systemd/Dockerfile.j2 create mode 100644 roles/service_status/molecule/systemd/molecule.yml create mode 100644 roles/service_status/molecule/systemd/playbook.yml create mode 100644 roles/service_status/molecule/systemd/prepare.yml create mode 100644 roles/service_status/tasks/containers.yaml create mode 100644 roles/service_status/tasks/main.yaml create mode 100644 roles/service_status/tasks/systemd.yaml create mode 100644 roles/stonith_exists/molecule/default/Dockerfile.j2 create mode 100644 roles/stonith_exists/molecule/default/molecule.yml create mode 100644 roles/stonith_exists/molecule/default/playbook.yml create mode 100644 roles/stonith_exists/molecule/default/prepare.yml create mode 100644 roles/stonith_exists/tasks/main.yml create mode 100644 roles/stonith_exists/vars/main.yml create mode 100644 roles/undercloud_cpu/README.md create mode 100644 roles/undercloud_cpu/defaults/main.yml create mode 100644 roles/undercloud_cpu/molecule/default/Dockerfile.j2 create mode 100644 roles/undercloud_cpu/molecule/default/molecule.yml create mode 100644 roles/undercloud_cpu/molecule/default/playbook.yml create mode 100644 roles/undercloud_cpu/tasks/main.yml create mode 100644 roles/undercloud_cpu/vars/main.yaml create mode 100644 roles/undercloud_disk_space/README.md create mode 100644 roles/undercloud_disk_space/defaults/main.yml create mode 100644 roles/undercloud_disk_space/molecule/default/Dockerfile.j2 create mode 100644 roles/undercloud_disk_space/molecule/default/molecule.yml create mode 100644 roles/undercloud_disk_space/molecule/default/playbook.yml create mode 100644 roles/undercloud_disk_space/tasks/main.yml create mode 100644 roles/undercloud_disk_space/vars/main.yaml create mode 100644 roles/undercloud_ram/README.md create mode 100644 roles/undercloud_ram/defaults/main.yml create mode 100644 roles/undercloud_ram/molecule/default/Dockerfile.j2 create mode 100644 roles/undercloud_ram/molecule/default/molecule.yml create mode 100644 roles/undercloud_ram/molecule/default/playbook.yml create mode 100644 roles/undercloud_ram/tasks/main.yml create mode 100644 roles/undercloud_ram/vars/main.yaml create mode 100644 roles/undercloud_selinux_mode/README.md create mode 100644 roles/undercloud_selinux_mode/molecule/default/Dockerfile.j2 create mode 100644 roles/undercloud_selinux_mode/molecule/default/molecule.yml create mode 100644 roles/undercloud_selinux_mode/molecule/default/playbook.yml create mode 100644 roles/undercloud_selinux_mode/tasks/main.yml create mode 100644 roles/undercloud_selinux_mode/vars/main.yml create mode 100644 roles/undercloud_service_status/README.md create mode 100644 roles/undercloud_service_status/defaults/main.yml create mode 100644 roles/undercloud_service_status/tasks/main.yml create mode 100644 roles/undercloud_service_status/vars/main.yaml create mode 100644 roles/validate_selinux/defaults/main.yml create mode 100644 roles/validate_selinux/handlers/main.yml create mode 100644 roles/validate_selinux/molecule/default/Dockerfile create mode 100644 roles/validate_selinux/molecule/default/molecule.yml create mode 100644 roles/validate_selinux/molecule/default/playbook.yml create mode 100644 roles/validate_selinux/molecule/default/prepare.yml create mode 100644 roles/validate_selinux/molecule/default/verify.yml create mode 100644 roles/validate_selinux/tasks/main.yml create mode 100644 roles/validate_selinux/templates/skip-list.j2 create mode 100644 roles/validate_selinux/vars/main.yml create mode 100644 roles/xfs_check_ftype/molecule/default/Dockerfile.j2 create mode 100644 roles/xfs_check_ftype/molecule/default/molecule.yml create mode 100644 roles/xfs_check_ftype/molecule/default/playbook.yml create mode 100644 roles/xfs_check_ftype/molecule/default/prepare.yml create mode 100644 roles/xfs_check_ftype/molecule/default/verify.yml create mode 100644 roles/xfs_check_ftype/tasks/main.yml create mode 100644 roles/xfs_check_ftype/vars/main.yml create mode 100644 validations_common/tests/library/test_validations_read_ini.py diff --git a/library/haproxy_conf.py b/library/haproxy_conf.py new file mode 100644 index 0000000..de2e452 --- /dev/null +++ b/library/haproxy_conf.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# -*- coding: utf-8 -*- +# 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. + +import re + +from ansible.module_utils.basic import AnsibleModule +from yaml import safe_load as yaml_safe_load + +DOCUMENTATION = ''' +--- +module: haproxy_conf +short_description: Gather the HAProxy config +description: + - Gather the HAProxy config +options: + path: + required: true + description: + - file path to the config file + type: str +author: "Tomas Sedovic" +''' + +EXAMPLES = ''' +- hosts: webservers + tasks: + - name: Gather the HAProxy config + haproxy_conf: path=/etc/haproxy/haproxy.cfg +''' + + +# ConfigParser chokes on both mariadb and haproxy files. Luckily They have +# a syntax approaching ini config file so they are relatively easy to parse. +# This generic ini style config parser is not perfect -- it can ignore some +# valid options -- but good enough for our use case. +def generic_ini_style_conf_parser(file_path, section_regex, option_regex): + config = {} + current_section = None + with open(file_path) as config_file: + for line in config_file: + match_section = re.match(section_regex, line) + if match_section: + current_section = match_section.group(1) + config[current_section] = {} + match_option = re.match(option_regex, line) + if match_option and current_section: + option = re.sub(r'\s+', ' ', match_option.group(1)) + config[current_section][option] = match_option.group(2) + return config + + +def parse_haproxy_conf(file_path): + section_regex = r'^(\w+)' + option_regex = r'^(?:\s+)(\w+(?:\s+\w+)*?)\s+([\w/]*)$' + return generic_ini_style_conf_parser(file_path, section_regex, + option_regex) + + +def main(): + module = AnsibleModule( + argument_spec=yaml_safe_load(DOCUMENTATION)['options'] + ) + + haproxy_conf_path = module.params.get('path') + + try: + config = parse_haproxy_conf(haproxy_conf_path) + except IOError: + module.fail_json(msg="Could not open the haproxy conf file at: '%s'" % + haproxy_conf_path) + + module.exit_json(changed=False, ansible_facts={u'haproxy_conf': config}) + + +if __name__ == '__main__': + main() diff --git a/library/hiera.py b/library/hiera.py new file mode 100644 index 0000000..c5edd02 --- /dev/null +++ b/library/hiera.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# Copyright 2016 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + +import subprocess + +from ansible.module_utils.basic import AnsibleModule +from yaml import safe_load as yaml_safe_load + +DOCUMENTATION = ''' +--- +module: hiera +short_description: Get data from hiera +description: + - Get data from hiera +options: + name: + required: true + description: + - Name to lookup + type: str +author: "Martin Andre (@mandre)" +''' + +EXAMPLES = ''' +- hosts: webservers + tasks: + - name: Lookup foo + hiera: name=foo +''' + + +def main(): + module = AnsibleModule( + argument_spec=yaml_safe_load(DOCUMENTATION)['options'] + ) + + name = module.params.get('name') + + cmd = ['/usr/bin/hiera', '-c', '/etc/puppet/hiera.yaml', name] + result = subprocess.check_output(cmd, universal_newlines=True).rstrip() + + if result == 'nil': + module.fail_json(msg="Failed to retrieve hiera data for {}" + .format(name)) + + module.exit_json(changed=False, + ansible_facts={name: result}) + + +if __name__ == '__main__': + main() diff --git a/library/validations_read_ini.py b/library/validations_read_ini.py new file mode 100644 index 0000000..63cc4af --- /dev/null +++ b/library/validations_read_ini.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python + +# -*- coding: utf-8 -*- +# 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. + +# Ansible module to read a value from an Ini file. +# Usage: +# - validations_read_ini: path=/path/to/file.ini section=default key=something +# register: my_ini +# +# This will read the `path/to/file.ini` file and read the `Hello!` value under: +# [default] +# something = Hello! +# +# You can register the result and use it later with `{{ my_ini.value }}` + +try: + import configparser as ConfigParser +except ImportError: + import ConfigParser + +from enum import Enum +import os + +from ansible.module_utils.basic import AnsibleModule +from yaml import safe_load as yaml_safe_load + + +# Possible return values +class ReturnValue(Enum): + OK = 0 + INVALID_FORMAT = 1 + KEY_NOT_FOUND = 2 + + +def check_file(path, ignore_missing): + '''Validate entered path''' + + if not (os.path.exists(path) and os.path.isfile(path)): + return "Could not open the ini file: '{}'".format(path) + else: + return '' + + +def get_result(path, section, key, default=None): + '''Get value based on section and key''' + + msg = '' + value = None + config = ConfigParser.SafeConfigParser() + + try: + config.read(path) + except Exception: + msg = "The file '{}' is not in a valid INI format.".format(path) + ret = ReturnValue.INVALID_FORMAT + return (ret, msg, value) + + try: + value = config.get(section, key) + msg = ("The key '{}' under the section '{}' in file {} " + "has the value: '{}'").format(key, section, path, value) + ret = ReturnValue.OK + return (ret, msg, value) + except ConfigParser.Error: + if default: + msg = ("There is no key '{}' under section '{}' in file {}. Using" + " default value '{}'".format(key, section, path, default)) + ret = ReturnValue.OK + value = default + else: + value = None + msg = "There is no key '{}' under the section '{}' in file {}.".format( + key, section, path) + ret = ReturnValue.KEY_NOT_FOUND + return (ret, msg, value) + + +DOCUMENTATION = ''' +--- +module: validations_read_ini +short_description: Get data from an ini file +description: + - Get data from an ini file +options: + path: + required: true + description: + - File path + type: str + section: + required: true + description: + - Section to look up + type: str + key: + required: true + description: + - Section key to look up + type: str + default: + required: false + description: + - Default value if key isn't found + ignore_missing_file: + required: false + description: + - Flag if a missing file should be ignored + type: bool +author: "Tomas Sedovic" +''' + +EXAMPLES = ''' +- hosts: webservers + tasks: + - name: Lookup bar value + validations_read_ini: path=config.ini section=foo key=bar ignore_missing_file=True +''' + + +def main(): + module = AnsibleModule( + argument_spec=yaml_safe_load(DOCUMENTATION)['options'] + ) + + ini_file_path = module.params.get('path') + ignore_missing = module.params.get('ignore_missing_file') + + # Check that file exists + msg = check_file(ini_file_path, ignore_missing) + + if msg != '': + # Opening file failed + if ignore_missing: + module.exit_json(msg=msg, changed=False, value=None) + else: + module.fail_json(msg=msg) + else: + # Try to parse the result from ini file + section = module.params.get('section') + key = module.params.get('key') + default = module.params.get('default') + + ret, msg, value = get_result(ini_file_path, section, key, default) + + if ret == ReturnValue.INVALID_FORMAT: + module.fail_json(msg=msg) + elif ret == ReturnValue.KEY_NOT_FOUND: + module.exit_json(msg=msg, changed=False, value=None) + elif ret == ReturnValue.OK: + module.exit_json(msg=msg, changed=False, value=value) + + +if __name__ == '__main__': + main() diff --git a/library/warn.py b/library/warn.py new file mode 100644 index 0000000..61852f3 --- /dev/null +++ b/library/warn.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# Copyright 2017 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + +from ansible.module_utils.basic import AnsibleModule +from yaml import safe_load as yaml_safe_load + +DOCUMENTATION = ''' +--- +module: warn +short_description: Add warning to playbook output +description: + - Add warning to playbook output +options: + msg: + required: true + description: + - The warning text + type: str +author: "Martin Andre (@mandre)" +''' + +EXAMPLES = ''' +- hosts: webservers + tasks: + - name: Output warning message + warn: msg="Warning!" +''' + + +def main(): + module = AnsibleModule( + argument_spec=yaml_safe_load(DOCUMENTATION)['options'] + ) + + msg = module.params.get('msg') + + module.exit_json(changed=False, + warnings=[msg]) + + +if __name__ == '__main__': + main() diff --git a/roles/advanced_format_512e_support/molecule/default/Dockerfile.j2 b/roles/advanced_format_512e_support/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/advanced_format_512e_support/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/advanced_format_512e_support/molecule/default/molecule.yml b/roles/advanced_format_512e_support/molecule/default/molecule.yml new file mode 100644 index 0000000..f87e178 --- /dev/null +++ b/roles/advanced_format_512e_support/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools python-enum34 python-netaddr ruby epel-release PyYAML + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools python*-enum python*-netaddr ruby PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/advanced_format_512e_support/molecule/default/playbook.yml b/roles/advanced_format_512e_support/molecule/default/playbook.yml new file mode 100644 index 0000000..6c61a39 --- /dev/null +++ b/roles/advanced_format_512e_support/molecule/default/playbook.yml @@ -0,0 +1,26 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + tasks: + - name: Warn developers about the lack of molecule testing + fail: + msg: >- + This role needs molecule tests! diff --git a/roles/advanced_format_512e_support/tasks/main.yml b/roles/advanced_format_512e_support/tasks/main.yml new file mode 100644 index 0000000..0d507e0 --- /dev/null +++ b/roles/advanced_format_512e_support/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: List the available drives + register: drive_list + command: "ls /sys/class/block/" + changed_when: false + +- name: Detect whether the drive uses Advanced Format + advanced_format: drive={{ item }} + when: item is match("^sd.$") + with_items: "{{ drive_list.stdout_lines }}" diff --git a/roles/advanced_format_512e_support/vars/main.yml b/roles/advanced_format_512e_support/vars/main.yml new file mode 100644 index 0000000..6ed23ac --- /dev/null +++ b/roles/advanced_format_512e_support/vars/main.yml @@ -0,0 +1,9 @@ +--- +metadata: + name: Advanced Format 512e Support + description: > + Detect whether the undercloud disks use Advanced Format. If they do, + the overcloud images may fail to upload to Glance. + groups: + - prep + - pre-deployment diff --git a/roles/check_latest_packages_version/defaults/main.yml b/roles/check_latest_packages_version/defaults/main.yml new file mode 100644 index 0000000..e8e9d2e --- /dev/null +++ b/roles/check_latest_packages_version/defaults/main.yml @@ -0,0 +1,10 @@ +--- +tripleoclient: >- + {%- if ansible_distribution == 'RedHat' and ansible_distribution_major_version == '8' -%} + python3-tripleoclient + {%- else -%} + python2-tripleoclient + {%- endif -%} + +packages: + - "{{ tripleoclient }}" diff --git a/roles/check_latest_packages_version/molecule/default/Dockerfile.j2 b/roles/check_latest_packages_version/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/check_latest_packages_version/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/check_latest_packages_version/molecule/default/molecule.yml b/roles/check_latest_packages_version/molecule/default/molecule.yml new file mode 100644 index 0000000..b78ef8d --- /dev/null +++ b/roles/check_latest_packages_version/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools PyYAML + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/check_latest_packages_version/molecule/default/playbook.yml b/roles/check_latest_packages_version/molecule/default/playbook.yml new file mode 100644 index 0000000..db4a659 --- /dev/null +++ b/roles/check_latest_packages_version/molecule/default/playbook.yml @@ -0,0 +1,51 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + + tasks: + - name: Validate No Available Update for patch rpm + include_role: + name: check_latest_packages_version + vars: + packages: + - patch + + - name: Working Detection of Update for Pam package + block: + - include_role: + name: check_latest_packages_version + vars: + packages: + - pam + + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The check_latest_packages_version role should have detected + that packages have available updates. diff --git a/roles/check_latest_packages_version/molecule/default/prepare.yml b/roles/check_latest_packages_version/molecule/default/prepare.yml new file mode 100644 index 0000000..c55cfc7 --- /dev/null +++ b/roles/check_latest_packages_version/molecule/default/prepare.yml @@ -0,0 +1,25 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Prepare + hosts: all + gather_facts: false + + tasks: + - name: install patch rpm + package: + name: patch diff --git a/roles/check_latest_packages_version/tasks/main.yml b/roles/check_latest_packages_version/tasks/main.yml new file mode 100644 index 0000000..dd782ea --- /dev/null +++ b/roles/check_latest_packages_version/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: Get available updates for packages + check_package_update: + package: "{{ item }}" + pkg_mgr: "{{ ansible_pkg_mgr }}" + with_items: "{{ packages }}" + register: updates + +- name: Check if current version is the latest one + fail: + msg: >- + A newer version of the {{ item.name }} package is + available: {{ item.new_version }}-{{ item.new_release }} + (currently {{ item.current_version }}-{{ item.current_release }}) + with_items: "{{ updates.results }}" + when: item.new_version diff --git a/roles/check_latest_packages_version/vars/main.yml b/roles/check_latest_packages_version/vars/main.yml new file mode 100644 index 0000000..fa84039 --- /dev/null +++ b/roles/check_latest_packages_version/vars/main.yml @@ -0,0 +1,8 @@ +--- +metadata: + name: Check if latest version of packages is installed + description: > + Makes sure python-tripleoclient is at its latest version + before starting an upgrade. + groups: + - pre-upgrade diff --git a/roles/dns/defaults/main.yml b/roles/dns/defaults/main.yml new file mode 100644 index 0000000..bb0cae8 --- /dev/null +++ b/roles/dns/defaults/main.yml @@ -0,0 +1,2 @@ +--- +server_to_lookup: example.com diff --git a/roles/dns/molecule/default/Dockerfile.j2 b/roles/dns/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/dns/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/dns/molecule/default/molecule.yml b/roles/dns/molecule/default/molecule.yml new file mode 100644 index 0000000..5eb59c2 --- /dev/null +++ b/roles/dns/molecule/default/molecule.yml @@ -0,0 +1,46 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/dns/molecule/default/playbook.yml b/roles/dns/molecule/default/playbook.yml new file mode 100644 index 0000000..1a6d6bd --- /dev/null +++ b/roles/dns/molecule/default/playbook.yml @@ -0,0 +1,47 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + + tasks: + - name: Should get a success + include_role: + name: dns + vars: + server_to_lookup: www.redhat.com + - name: Should properly fail + block: + - include_role: + name: dns + vars: + server_to_lookup: role.dns.domain.do-not.exists + + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The dns role should have detected a faulty DNS configuration diff --git a/roles/dns/tasks/main.yml b/roles/dns/tasks/main.yml new file mode 100644 index 0000000..aefea08 --- /dev/null +++ b/roles/dns/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Ensure DNS resolution works + command: "getent hosts {{ server_to_lookup }}" + changed_when: false diff --git a/roles/dns/vars/main.yml b/roles/dns/vars/main.yml new file mode 100644 index 0000000..e3e6f38 --- /dev/null +++ b/roles/dns/vars/main.yml @@ -0,0 +1,7 @@ +--- +metadata: + name: Verify DNS + description: > + Verify that the DNS resolution works + groups: + - pre-deployment diff --git a/roles/haproxy/README.md b/roles/haproxy/README.md new file mode 100644 index 0000000..8c10180 --- /dev/null +++ b/roles/haproxy/README.md @@ -0,0 +1,42 @@ +haproxy +======= + +An Ansible role to check if the HAProxy configuration has recommended values. + +Requirements +------------ + +This role requires an Up and Running Overcloud + +Role Variables +-------------- + +- config_file: '/var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg' +- global_maxconn_min: 20480 +- defaults_maxconn_min: 4096 +- defaults_timeout_queue: '2m' +- defaults_timeout_client: '2m' +- defaults_timeout_server: '2m' +- defaults_timeout_check: '10s' + +Dependencies +------------ + +No dependencies + +Example Playbook +---------------- + + - hosts: undercloud + roles: + - { role: haproxy } + +License +------- + +Apache + +Author Information +------------------ + +Red Hat TripleO Validations Team. diff --git a/roles/haproxy/defaults/main.yml b/roles/haproxy/defaults/main.yml new file mode 100644 index 0000000..4cd0eb2 --- /dev/null +++ b/roles/haproxy/defaults/main.yml @@ -0,0 +1,8 @@ +--- +haproxy_config_file: '/var/lib/config-data/puppet-generated/haproxy/etc/haproxy/haproxy.cfg' +global_maxconn_min: 20480 +defaults_maxconn_min: 4096 +defaults_timeout_queue: '2m' +defaults_timeout_client: '2m' +defaults_timeout_server: '2m' +defaults_timeout_check: '10s' diff --git a/roles/haproxy/molecule/default/Dockerfile.j2 b/roles/haproxy/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..a2e66f4 --- /dev/null +++ b/roles/haproxy/molecule/default/Dockerfile.j2 @@ -0,0 +1,36 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/haproxy/molecule/default/molecule.yml b/roles/haproxy/molecule/default/molecule.yml new file mode 100644 index 0000000..9fa3f4c --- /dev/null +++ b/roles/haproxy/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools haproxy PyYAML + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools haproxy PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: true + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/haproxy/molecule/default/playbook.yml b/roles/haproxy/molecule/default/playbook.yml new file mode 100644 index 0000000..9960f97 --- /dev/null +++ b/roles/haproxy/molecule/default/playbook.yml @@ -0,0 +1,71 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + vars: + haproxy_config_file: /haproxy.cfg + + tasks: + - name: create haproxy config file + copy: + dest: /haproxy.cfg + content: | + # This file managed by Puppet + global + daemon + group haproxy + log /dev/log local0 + maxconn 100 + pidfile /var/run/haproxy.pid + ssl-default-bind-ciphers !SSLv2:kEECDH:kRSA:kEDH:kPSK:+3DES:!aNULL:!eNULL:!MD5:!EXP:!RC4:!SEED:!IDEA:!DES + ssl-default-bind-options no-sslv3 no-tlsv10 + stats socket /var/lib/haproxy/stats mode 600 level user + stats timeout 1s + user haproxy + + defaults + log global + maxconn 100 + mode tcp + retries 1 + timeout http-request 1s + timeout queue 1s + timeout connect 1s + timeout client 1s + timeout server 1s + timeout check 1s + - block: + - include_role: + name: haproxy + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The haproxy role should have detected issues within haproxy + configuration file! diff --git a/roles/haproxy/tasks/main.yml b/roles/haproxy/tasks/main.yml new file mode 100644 index 0000000..6ed7b80 --- /dev/null +++ b/roles/haproxy/tasks/main.yml @@ -0,0 +1,51 @@ +--- +- name: Gather the HAProxy config + become: true + haproxy_conf: + path: "{{ haproxy_config_file }}" + +- name: Verify global maxconn + fail: + msg: >- + The 'global maxconn' value '{{ haproxy_conf.global.maxconn }}' + must be greater than {{ global_maxconn_min }} + failed_when: haproxy_conf.global.maxconn|int < global_maxconn_min + +- name: Verify defaults maxconn + fail: + msg: >- + The 'defaults maxconn' value '{{ haproxy_conf.defaults.maxconn }}' + must be greater than {{ defaults_maxconn_min }} + failed_when: haproxy_conf.defaults.maxconn|int < defaults_maxconn_min + +- name: Verify defaults timeout queue + fail: + msg: >- + The 'timeout queue' option in 'defaults' is + '{{ haproxy_conf.defaults['timeout queue'] }}', + but must be set to {{ defaults_timeout_queue }} + failed_when: "haproxy_conf.defaults['timeout queue'] != defaults_timeout_queue" + +- name: Verify defaults timeout client + fail: + msg: >- + The 'timeout client' option in 'defaults' is + '{{ haproxy_conf.defaults['timeout client'] }}', + but must be set to {{ defaults_timeout_client }} + failed_when: "haproxy_conf.defaults['timeout client'] != defaults_timeout_client" + +- name: Verify defaults timeout server + fail: + msg: >- + The 'timeout server' option in 'defaults' is + '{{ haproxy_conf.defaults['timeout server'] }}', + but must be set to {{ defaults_timeout_server }} + failed_when: "haproxy_conf.defaults['timeout server'] != defaults_timeout_server" + +- name: Verify defaults timeout check + fail: + msg: >- + The 'timeout check' option in 'defaults' is + '{{ haproxy_conf.defaults['timeout check'] }}', + but must be set to {{ defaults_timeout_check }} + failed_when: "haproxy_conf.defaults['timeout check'] != defaults_timeout_check" diff --git a/roles/haproxy/vars/main.yml b/roles/haproxy/vars/main.yml new file mode 100644 index 0000000..a04d0e8 --- /dev/null +++ b/roles/haproxy/vars/main.yml @@ -0,0 +1,6 @@ +--- +metadata: + name: HAProxy configuration + description: Verify the HAProxy configuration has recommended values. + groups: + - post-deployment diff --git a/roles/no_op/tasks/main.yml b/roles/no_op/tasks/main.yml new file mode 100644 index 0000000..904ba20 --- /dev/null +++ b/roles/no_op/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Run a no-op validation everywhere + debug: + msg: "This is a no-op action for testing that the validations framework runs" diff --git a/roles/no_op/vars/main.yml b/roles/no_op/vars/main.yml new file mode 100644 index 0000000..4202d35 --- /dev/null +++ b/roles/no_op/vars/main.yml @@ -0,0 +1,8 @@ +--- +metadata: + name: NO-OP validation + description: > + A simple validation doing nothing in order to test that + the validations framework works. + groups: + - no-op diff --git a/roles/ntp/molecule/default/Dockerfile.j2 b/roles/ntp/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/ntp/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/ntp/molecule/default/molecule.yml b/roles/ntp/molecule/default/molecule.yml new file mode 100644 index 0000000..f87e178 --- /dev/null +++ b/roles/ntp/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools python-enum34 python-netaddr ruby epel-release PyYAML + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools python*-enum python*-netaddr ruby PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/ntp/molecule/default/playbook.yml b/roles/ntp/molecule/default/playbook.yml new file mode 100644 index 0000000..6c61a39 --- /dev/null +++ b/roles/ntp/molecule/default/playbook.yml @@ -0,0 +1,26 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + tasks: + - name: Warn developers about the lack of molecule testing + fail: + msg: >- + This role needs molecule tests! diff --git a/roles/ntp/tasks/main.yml b/roles/ntp/tasks/main.yml new file mode 100644 index 0000000..36c67fa --- /dev/null +++ b/roles/ntp/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: Get if chrony is enabled + become: true + hiera: + name: "chrony_enabled" + +- when: chrony_enabled|bool + block: + - name: Populate service facts + service_facts: # needed to make yaml happy + + - name: Fail if chronyd service is not running + fail: + msg: "Chronyd service is not running" + when: "ansible_facts.services['chronyd.service'].state != 'running'" + + - name: Run chronyc + become: true + command: chronyc -a 'burst 4/4' + changed_when: false + +# ntpstat returns 0 if synchronised and non-zero otherwise: +- name: Run ntpstat + command: ntpstat + changed_when: false + when: not chrony_enabled|bool diff --git a/roles/ntp/vars/main.yml b/roles/ntp/vars/main.yml new file mode 100644 index 0000000..992ea6f --- /dev/null +++ b/roles/ntp/vars/main.yml @@ -0,0 +1,10 @@ +--- +metadata: + name: Verify all deployed nodes have their clock synchronised + description: > + Each overcloud node should have their clocks synchronised. + + The deployment should configure and run chronyd. This validation verifies + that it is indeed running and connected to an NTP server on all nodes. + groups: + - post-deployment diff --git a/roles/service_status/defaults/main.yaml b/roles/service_status/defaults/main.yaml new file mode 100644 index 0000000..87e9c20 --- /dev/null +++ b/roles/service_status/defaults/main.yaml @@ -0,0 +1,2 @@ +--- +service_status_podman_opt: '' diff --git a/roles/service_status/molecule/default/Dockerfile.j2 b/roles/service_status/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/service_status/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/service_status/molecule/default/molecule.yml b/roles/service_status/molecule/default/molecule.yml new file mode 100644 index 0000000..b8430d5 --- /dev/null +++ b/roles/service_status/molecule/default/molecule.yml @@ -0,0 +1,49 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools python-enum34 python-netaddr ruby epel-release PyYAML + easy_install: + - pip + command: /sbin/init + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + command: /sbin/init + pkg_extras: python*-setuptools python*-enum python*-netaddr ruby PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/service_status/molecule/default/playbook.yml b/roles/service_status/molecule/default/playbook.yml new file mode 100644 index 0000000..39290cd --- /dev/null +++ b/roles/service_status/molecule/default/playbook.yml @@ -0,0 +1,25 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + tasks: + - name: Full check with defaults + include_role: + name: service_status diff --git a/roles/service_status/molecule/docker/Dockerfile.j2 b/roles/service_status/molecule/docker/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/service_status/molecule/docker/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/service_status/molecule/docker/molecule.yml b/roles/service_status/molecule/docker/molecule.yml new file mode 100644 index 0000000..c4b5b91 --- /dev/null +++ b/roles/service_status/molecule/docker/molecule.yml @@ -0,0 +1,61 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools python-enum34 python-netaddr ruby epel-release PyYAML + easy_install: + - pip + command: /sbin/init + capabilities: + - SYS_ADMIN + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /sys/fs/cgroup:/sys/fs/cgroup:ro + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + command: /sbin/init + capabilities: + - SYS_ADMIN + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /sys/fs/cgroup:/sys/fs/cgroup:ro + pkg_extras: python*-setuptools python*-enum python*-netaddr ruby PyYAML python*-libselinux + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/service_status/molecule/docker/playbook.yml b/roles/service_status/molecule/docker/playbook.yml new file mode 100644 index 0000000..b3db61a --- /dev/null +++ b/roles/service_status/molecule/docker/playbook.yml @@ -0,0 +1,59 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + become: true + + tasks: + - name: "Check containers - docker version, no service" + include_role: + name: service_status + tasks_from: containers.yaml + + - name: "Check containers - docker version, with service" + block: + - name: Activate docker service + service: + name: docker + state: started + enabled: true + + - name: Catch failure + block: + - name: Run check + include_role: + name: service_status + tasks_from: containers.yaml + + rescue: + - name: Clear host errors + meta: clear_host_errors + + - name: Test output + debug: + msg: | + Success finding broken containers + + - name: End play + meta: end_play + + - name: Fail if this point is reached + fail: + msg: | + Did not find broken containers diff --git a/roles/service_status/molecule/docker/prepare.yml b/roles/service_status/molecule/docker/prepare.yml new file mode 100644 index 0000000..eb96fe0 --- /dev/null +++ b/roles/service_status/molecule/docker/prepare.yml @@ -0,0 +1,65 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Prepare + hosts: all + gather_facts: false + + tasks: + - name: install docker + package: + name: docker + + - name: fake docker exe + copy: + dest: /usr/bin/docker + mode: 0755 + content: | + #!/bin/sh + echo 'thirsty_goldwasser Exited (0) 12 seconds ago' + echo 'fedora28 Exited (255) 7 hours ago' + echo 'centos7 Exited (255) 7 hours ago' + + - name: docker unit override basedir + file: + path: /etc/systemd/system/docker.service.d + state: directory + + - name: fake docker unit + copy: + dest: /etc/systemd/system/docker.service.d/override.conf + content: | + [Unit] + After=network.target + Wants= + Requires= + + [Service] + Type=simple + ExecStart= + ExecStart=/usr/bin/fake + Restart= + + - name: fake docker exec for unit + copy: + dest: /usr/bin/fake + mode: 0755 + content: | + #!/bin/sh + while true; do + sleep 5; + done diff --git a/roles/service_status/molecule/podman/Dockerfile.j2 b/roles/service_status/molecule/podman/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/service_status/molecule/podman/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/service_status/molecule/podman/bolt_state.db b/roles/service_status/molecule/podman/bolt_state.db new file mode 100644 index 0000000000000000000000000000000000000000..bab3585b96e89856d5d2c1cf3681a5637486b875 GIT binary patch literal 131072 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 + {% raw %} + docker ps -a --filter 'status=exited' --format '{{ .Names }} {{ .Status }}' + {% endraw %} + register: failed_docker + + - name: Fail if we detect failed docker container + fail: + msg: | + Failed container detected. + On CI, please check the following locations + /var/log/extras/failed_containers.log + /var/log/extras/docker + when: + - failed_docker is defined + - item is not match(".* Exited \(0\) .* ago") + loop: "{{ failed_docker.stdout_lines }}" diff --git a/roles/service_status/tasks/main.yaml b/roles/service_status/tasks/main.yaml new file mode 100644 index 0000000..8e23251 --- /dev/null +++ b/roles/service_status/tasks/main.yaml @@ -0,0 +1,3 @@ +--- +- include_tasks: containers.yaml +- include_tasks: systemd.yaml diff --git a/roles/service_status/tasks/systemd.yaml b/roles/service_status/tasks/systemd.yaml new file mode 100644 index 0000000..a7b726b --- /dev/null +++ b/roles/service_status/tasks/systemd.yaml @@ -0,0 +1,13 @@ +--- +- name: Get failed services from Systemd + shell: > + systemctl list-units --failed --plain --no-legend --no-pager "tripleo_*" + register: systemd_state + changed_when: false + +- name: Fails if we find failed systemd units + assert: + that: + - systemd_state.stdout_lines|length == 0 + fail_msg: "The following services failed {{ systemd_state.stdout_lines }}" + success_msg: "All tripleo units are working fine" diff --git a/roles/stonith_exists/molecule/default/Dockerfile.j2 b/roles/stonith_exists/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/stonith_exists/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/stonith_exists/molecule/default/molecule.yml b/roles/stonith_exists/molecule/default/molecule.yml new file mode 100644 index 0000000..5eb59c2 --- /dev/null +++ b/roles/stonith_exists/molecule/default/molecule.yml @@ -0,0 +1,46 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/stonith_exists/molecule/default/playbook.yml b/roles/stonith_exists/molecule/default/playbook.yml new file mode 100644 index 0000000..aefd9ff --- /dev/null +++ b/roles/stonith_exists/molecule/default/playbook.yml @@ -0,0 +1,56 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + + tasks: + - name: Safe run + include_role: + name: stonith_exists + + - name: Fail the validation + block: + - name: Faulty pcs script + copy: + dest: /usr/bin/pcs + mode: 0755 + content: | + #!/bin/sh + echo "NO stonith devices configured" + exit 0 + + - name: Run validation + include_role: + name: stonith_exists + + rescue: + - name: Clear host errors + meta: clear_host_errors + + - name: Test output + debug: + msg: The validation works! End play + + - name: End play + meta: end_play + + - name: Fail playbook if reached + fail: + msg: | + The stonith_exists validation didn't properly detect failed + stonith config diff --git a/roles/stonith_exists/molecule/default/prepare.yml b/roles/stonith_exists/molecule/default/prepare.yml new file mode 100644 index 0000000..eba0c86 --- /dev/null +++ b/roles/stonith_exists/molecule/default/prepare.yml @@ -0,0 +1,30 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Prepare + hosts: all + gather_facts: false + + tasks: + - name: Populate successful stonith + copy: + dest: /usr/bin/pcs + mode: 0755 + content: | + #!/bin/sh + echo "Stonith service configured" + exit 0 diff --git a/roles/stonith_exists/tasks/main.yml b/roles/stonith_exists/tasks/main.yml new file mode 100644 index 0000000..4277134 --- /dev/null +++ b/roles/stonith_exists/tasks/main.yml @@ -0,0 +1,22 @@ +--- +- name: Check if we are in HA cluster environment + become: true + register: pcs_cluster_status + command: pcs cluster status + failed_when: false + changed_when: false + +- name: Get all currently configured stonith devices + become: true + command: "pcs stonith" + register: stonith_devices + changed_when: false + when: "pcs_cluster_status.rc == 0" + +- name: Verify the stonith device are configured + fail: + msg: "Stonith devices are not configured." + when: > + pcs_cluster_status.rc == 0 + and + 'NO stonith devices configured' in stonith_devices.stdout diff --git a/roles/stonith_exists/vars/main.yml b/roles/stonith_exists/vars/main.yml new file mode 100644 index 0000000..34a26d1 --- /dev/null +++ b/roles/stonith_exists/vars/main.yml @@ -0,0 +1,11 @@ +--- +metadata: + name: Validate stonith devices + description: > + Verify that stonith devices are configured for your OpenStack Platform HA cluster. + We don't configure stonith device with TripleO Installer. Because the hardware + configuration may be differ in each environment and requires different fence agents. + How to configure fencing please read + https://access.redhat.com/documentation/en/red-hat-openstack-platform/8/paged/director-installation-and-usage/86-fencing-the-controller-nodes + groups: + - post-deployment diff --git a/roles/undercloud_cpu/README.md b/roles/undercloud_cpu/README.md new file mode 100644 index 0000000..3b7728a --- /dev/null +++ b/roles/undercloud_cpu/README.md @@ -0,0 +1,36 @@ +Undercloud-cpu +============== + +An Ansible role to check if the Undercloud fits the CPU core requirements + +Requirements +------------ + +This role could be used before or/and after the Undercloud installation. + +Role Variables +-------------- + +- min_undercloud_cpu_count: <8> -- Minimal number of CPU core + +Dependencies +------------ + +No dependencies. + +Example Playbook +---------------- + + - hosts: undercloud + roles: + - { role: undercloud-cpu, min_undercloud_cpu_count: 42 } + +License +------- + +Apache 2.0 + +Author Information +------------------ + +Red Hat TripleO Validations Team diff --git a/roles/undercloud_cpu/defaults/main.yml b/roles/undercloud_cpu/defaults/main.yml new file mode 100644 index 0000000..5a15292 --- /dev/null +++ b/roles/undercloud_cpu/defaults/main.yml @@ -0,0 +1,3 @@ +--- + +min_undercloud_cpu_count: 8 diff --git a/roles/undercloud_cpu/molecule/default/Dockerfile.j2 b/roles/undercloud_cpu/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/undercloud_cpu/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/undercloud_cpu/molecule/default/molecule.yml b/roles/undercloud_cpu/molecule/default/molecule.yml new file mode 100644 index 0000000..5eb59c2 --- /dev/null +++ b/roles/undercloud_cpu/molecule/default/molecule.yml @@ -0,0 +1,46 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/undercloud_cpu/molecule/default/playbook.yml b/roles/undercloud_cpu/molecule/default/playbook.yml new file mode 100644 index 0000000..f6802bf --- /dev/null +++ b/roles/undercloud_cpu/molecule/default/playbook.yml @@ -0,0 +1,42 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + + vars: + min_undercloud_cpu_count: 100 + + tasks: + - block: + - include_role: + name: undercloud_cpu + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The undercloud_cpu role should have detected that there is not + enough CPU diff --git a/roles/undercloud_cpu/tasks/main.yml b/roles/undercloud_cpu/tasks/main.yml new file mode 100644 index 0000000..eeb0031 --- /dev/null +++ b/roles/undercloud_cpu/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: Verify the number of CPU cores + fail: + msg: >- + There are {{ ansible_processor_vcpus }} cores in the system, + but there should be at least {{ min_undercloud_cpu_count }} + failed_when: "ansible_processor_vcpus|int < min_undercloud_cpu_count|int" diff --git a/roles/undercloud_cpu/vars/main.yaml b/roles/undercloud_cpu/vars/main.yaml new file mode 100644 index 0000000..2766e82 --- /dev/null +++ b/roles/undercloud_cpu/vars/main.yaml @@ -0,0 +1,10 @@ +--- +metadata: + name: Verify undercloud fits the CPU core requirements + description: > + Make sure that the undercloud has enough CPU cores. + + https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux_OpenStack_Platform/7/html/Director_Installation_and_Usage/sect-Undercloud_Requirements.html + groups: + - prep + - pre-introspection diff --git a/roles/undercloud_disk_space/README.md b/roles/undercloud_disk_space/README.md new file mode 100644 index 0000000..73bf492 --- /dev/null +++ b/roles/undercloud_disk_space/README.md @@ -0,0 +1,36 @@ +Undercloud-disk-space +===================== + +An Ansible role to verify if the Undercloud fits the disk space requirements. + +Requirements +------------ + +This role could be used before or/and after the Undercloud installation. + +Role Variables +-------------- + +- Volumes: a dictionary of mount points and their minimum sizes + +Dependencies +------------ + +No Dependencies + +Example Playbook +---------------- + + - hosts: servers + roles: + - { role: undercloud-disk-space} + +License +------- + +Apache + +Author Information +------------------ + +Red Hat TripleO Validation Team diff --git a/roles/undercloud_disk_space/defaults/main.yml b/roles/undercloud_disk_space/defaults/main.yml new file mode 100644 index 0000000..1484cfd --- /dev/null +++ b/roles/undercloud_disk_space/defaults/main.yml @@ -0,0 +1,8 @@ +--- +volumes: + - {mount: /var/lib/docker, min_size: 10} + - {mount: /var/lib/config-data, min_size: 3} + - {mount: /var/log, min_size: 3} + - {mount: /usr, min_size: 5} + - {mount: /var, min_size: 20} + - {mount: /, min_size: 25} diff --git a/roles/undercloud_disk_space/molecule/default/Dockerfile.j2 b/roles/undercloud_disk_space/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/undercloud_disk_space/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/undercloud_disk_space/molecule/default/molecule.yml b/roles/undercloud_disk_space/molecule/default/molecule.yml new file mode 100644 index 0000000..5eb59c2 --- /dev/null +++ b/roles/undercloud_disk_space/molecule/default/molecule.yml @@ -0,0 +1,46 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/undercloud_disk_space/molecule/default/playbook.yml b/roles/undercloud_disk_space/molecule/default/playbook.yml new file mode 100644 index 0000000..31826ae --- /dev/null +++ b/roles/undercloud_disk_space/molecule/default/playbook.yml @@ -0,0 +1,44 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + vars: + volumes: + - {mount: /var, min_size: 20} + - {mount: /, min_size: 150} + + tasks: + - block: + - include_role: + name: undercloud_disk_space + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The validation did not detect a too small disk space diff --git a/roles/undercloud_disk_space/tasks/main.yml b/roles/undercloud_disk_space/tasks/main.yml new file mode 100644 index 0000000..67c989b --- /dev/null +++ b/roles/undercloud_disk_space/tasks/main.yml @@ -0,0 +1,39 @@ +--- +- name: Set a constant defining number of Bytes in 1 GB + set_fact: + const_bytes_in_gb: 1073741824 + +- name: Stat volume directories + stat: + path: "{{ item.mount }}" + with_items: "{{ volumes }}" + register: volumes_stat + +- name: Initialize existing_volumes to an empty array + set_fact: + existing_volumes="{{ [] }}" + +- name: Filter out non-existing volumes + set_fact: + existing_volumes: "{{ existing_volumes +[item.item] }}" + with_items: "{{ volumes_stat.results }}" + when: item.stat.exists + loop_control: + label: "{{ item.item.mount }}" + +- name: Loop on volumes and gather available space + shell: df -B1 {{ item.mount }} --output=avail | sed 1d + register: volume_size + with_items: "{{ existing_volumes }}" + changed_when: false + +- name: Fail if any of the volumes are too small + fail: + msg: > + Minimum free space required for {{ item.item.mount }}: {{ item.item.min_size }}G + - current free space: {{ (item.stdout|int / const_bytes_in_gb|int) |round(1) }}G + when: > + item.stdout|int / const_bytes_in_gb|int < item.item.min_size|int + with_items: "{{ volume_size.results }}" + loop_control: + label: "{{ item.item.mount }}" diff --git a/roles/undercloud_disk_space/vars/main.yaml b/roles/undercloud_disk_space/vars/main.yaml new file mode 100644 index 0000000..69b5444 --- /dev/null +++ b/roles/undercloud_disk_space/vars/main.yaml @@ -0,0 +1,11 @@ +--- +metadata: + name: Verify undercloud fits the disk space requirements + description: > + Make sure that the root partition on the undercloud node has enough + free space. + + http://tripleo.org/install/environments/baremetal.html#minimum-system-requirements + groups: + - prep + - pre-introspection diff --git a/roles/undercloud_ram/README.md b/roles/undercloud_ram/README.md new file mode 100644 index 0000000..53224d1 --- /dev/null +++ b/roles/undercloud_ram/README.md @@ -0,0 +1,36 @@ +Undercloud-ram +============== + +An Ansible role to check if the Undercloud fits the RAM requirements + +Requirements +------------ + +This role could be used before or/and after the Undercloud installation + +Role Variables +-------------- + +- min_undercloud_ram_gb: <24> -- Minimal amount of RAM in GB + +Dependencies +------------ + +No dependencies. + +Example Playbook +---------------- + + - hosts: undercloud + roles: + - { role: undercloud-ram, min_undercloud_ram_gb: 24 } + +License +------- + +Apache + +Author Information +------------------ + +Red Hat TripleO Validations Team diff --git a/roles/undercloud_ram/defaults/main.yml b/roles/undercloud_ram/defaults/main.yml new file mode 100644 index 0000000..c9dbb34 --- /dev/null +++ b/roles/undercloud_ram/defaults/main.yml @@ -0,0 +1,3 @@ +--- + +min_undercloud_ram_gb: 24 diff --git a/roles/undercloud_ram/molecule/default/Dockerfile.j2 b/roles/undercloud_ram/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/undercloud_ram/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/undercloud_ram/molecule/default/molecule.yml b/roles/undercloud_ram/molecule/default/molecule.yml new file mode 100644 index 0000000..5eb59c2 --- /dev/null +++ b/roles/undercloud_ram/molecule/default/molecule.yml @@ -0,0 +1,46 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/undercloud_ram/molecule/default/playbook.yml b/roles/undercloud_ram/molecule/default/playbook.yml new file mode 100644 index 0000000..22e52b9 --- /dev/null +++ b/roles/undercloud_ram/molecule/default/playbook.yml @@ -0,0 +1,42 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + + vars: + min_undercloud_ram_gb: 1000000 + + tasks: + - block: + - include_role: + name: undercloud_ram + rescue: + - name: Clear host errors + meta: clear_host_errors + + - debug: + msg: The validation works! End the playbook run + + - name: End play + meta: end_play + + - name: Fail the test + fail: + msg: | + The undercloud_ram role should have detected that there is not + enough RAM diff --git a/roles/undercloud_ram/tasks/main.yml b/roles/undercloud_ram/tasks/main.yml new file mode 100644 index 0000000..bd2c4e9 --- /dev/null +++ b/roles/undercloud_ram/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: Verify the RAM requirements + fail: + msg: >- + The RAM on the undercloud node is {{ ansible_memtotal_mb }} MB, + the minimal recommended value is + {{ min_undercloud_ram_gb|int * 1024 }} MB. + # NOTE(shadower): converting GB to MB + failed_when: "(ansible_memtotal_mb) < min_undercloud_ram_gb|int * 1024" diff --git a/roles/undercloud_ram/vars/main.yaml b/roles/undercloud_ram/vars/main.yaml new file mode 100644 index 0000000..3bde5ed --- /dev/null +++ b/roles/undercloud_ram/vars/main.yaml @@ -0,0 +1,11 @@ +--- +metadata: + name: Verify the undercloud fits the RAM requirements + description: > + Verify that the undercloud has enough RAM. + + https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html/director_installation_and_usage/planning-your-undercloud#determining-environment-scale + groups: + - prep + - pre-introspection + - pre-upgrade diff --git a/roles/undercloud_selinux_mode/README.md b/roles/undercloud_selinux_mode/README.md new file mode 100644 index 0000000..eee51ef --- /dev/null +++ b/roles/undercloud_selinux_mode/README.md @@ -0,0 +1,37 @@ +Undercloud-selinux-mode +======================= + +An Ansible role to check the Undercloud SELinux Enforcing mode + + +Requirements +------------ + +This role could be used before or/and after the Undercloud installation + +Role Variables +-------------- + +None + +Dependencies +------------ + +No dependencies. + +Example Playbook +---------------- + + - hosts: undercloud + roles: + - { role: undercloud-selinux-mode } + +License +------- + +Apache + +Author Information +------------------ + +Red Hat TripleO Validations Team diff --git a/roles/undercloud_selinux_mode/molecule/default/Dockerfile.j2 b/roles/undercloud_selinux_mode/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/undercloud_selinux_mode/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/undercloud_selinux_mode/molecule/default/molecule.yml b/roles/undercloud_selinux_mode/molecule/default/molecule.yml new file mode 100644 index 0000000..f87e178 --- /dev/null +++ b/roles/undercloud_selinux_mode/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + pkg_extras: python-setuptools python-enum34 python-netaddr ruby epel-release PyYAML + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + pkg_extras: python*-setuptools python*-enum python*-netaddr ruby PyYAML + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/undercloud_selinux_mode/molecule/default/playbook.yml b/roles/undercloud_selinux_mode/molecule/default/playbook.yml new file mode 100644 index 0000000..6c61a39 --- /dev/null +++ b/roles/undercloud_selinux_mode/molecule/default/playbook.yml @@ -0,0 +1,26 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + + tasks: + - name: Warn developers about the lack of molecule testing + fail: + msg: >- + This role needs molecule tests! diff --git a/roles/undercloud_selinux_mode/tasks/main.yml b/roles/undercloud_selinux_mode/tasks/main.yml new file mode 100644 index 0000000..1cd8733 --- /dev/null +++ b/roles/undercloud_selinux_mode/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Get current SELinux mode + command: getenforce + become: true + register: sestatus + changed_when: false + +- name: Fail if SELinux is not in Enforced mode (RHEL) + fail: + msg: >- + SELinux is running in {{ sestatus.stdout }} mode on the Undercloud. + Ensure that SELinux is enabled and running in Enforcing mode. + when: + - "sestatus.stdout != 'Enforcing'" + - "ansible_distribution == 'RedHat'" + +- name: Warn if SELinux is not in Enforced mode (CentOS) + warn: + msg: >- + SELinux is running in {{ sestatus.stdout }} mode on the Undercloud. + Ensure that SELinux is enabled and running in Enforcing mode. + when: + - "sestatus.stdout != 'Enforcing'" + - "ansible_distribution == 'CentOS'" diff --git a/roles/undercloud_selinux_mode/vars/main.yml b/roles/undercloud_selinux_mode/vars/main.yml new file mode 100644 index 0000000..60e9515 --- /dev/null +++ b/roles/undercloud_selinux_mode/vars/main.yml @@ -0,0 +1,8 @@ +--- +metadata: + name: Undercloud SELinux Enforcing Mode Check + description: > + Check if the Undercloud is running SELinux in Enforcing mode. + groups: + - prep + - pre-introspection diff --git a/roles/undercloud_service_status/README.md b/roles/undercloud_service_status/README.md new file mode 100644 index 0000000..946bfa0 --- /dev/null +++ b/roles/undercloud_service_status/README.md @@ -0,0 +1,38 @@ +Undercloud-service-status +========================= + +An Ansible role to verify the Undercloud services states before running an +Update or Upgrade. + +Requirements +------------ + +This role needs to be run against an installed Undercloud. + +Role Variables +-------------- + +- undercloud_service_list: A list of services actually coming from the tripleo-ansible-inventory + +Dependencies +------------ + +No dependencies. + +Example Playbook +---------------- + + + - hosts: undercloud + roles: + - { role: undercloud-service-status } + +License +------- + +Apache + +Author Information +------------------ + +Red Hat TripleO Validations Team. diff --git a/roles/undercloud_service_status/defaults/main.yml b/roles/undercloud_service_status/defaults/main.yml new file mode 100644 index 0000000..e9e29ba --- /dev/null +++ b/roles/undercloud_service_status/defaults/main.yml @@ -0,0 +1,8 @@ +--- +undercloud_service_list: + - tripleo_nova_compute + - tripleo_heat_engine + - tripleo_ironic_conductor + - tripleo_swift_container_server + - tripleo_swift_object_server + - tripleo_mistral_engine diff --git a/roles/undercloud_service_status/tasks/main.yml b/roles/undercloud_service_status/tasks/main.yml new file mode 100644 index 0000000..8291e81 --- /dev/null +++ b/roles/undercloud_service_status/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Check Services are running + command: "/usr/bin/systemctl show {{ item }} --property ActiveState" + become: true + with_items: "{{ undercloud_service_list }}" + register: "check_services" + changed_when: false + ignore_errors: true + +- name: Fail if services were not running + fail: + msg: >- + One of the undercloud services was not active. + Please check {{ item.item }} first and then confirm the status of + undercloud services in general before attempting to update or + upgrade the environment. + failed_when: "item.stdout != 'ActiveState=active'" + with_items: "{{ check_services.results }}" diff --git a/roles/undercloud_service_status/vars/main.yaml b/roles/undercloud_service_status/vars/main.yaml new file mode 100644 index 0000000..f934d5c --- /dev/null +++ b/roles/undercloud_service_status/vars/main.yaml @@ -0,0 +1,8 @@ +--- +metadata: + name: Verify undercloud services state before running update or upgrade + description: > + Check undercloud status before running a stack update - especially minor update and major upgrade. + groups: + - post-upgrade + - pre-upgrade diff --git a/roles/validate_selinux/defaults/main.yml b/roles/validate_selinux/defaults/main.yml new file mode 100644 index 0000000..c7f0a32 --- /dev/null +++ b/roles/validate_selinux/defaults/main.yml @@ -0,0 +1,27 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +# All variables intended for modification should place placed in this file. + +# All variables within this role should have a prefix of "validate_selinux" +validate_selinux_working_dir: /var/log/validations +validate_selinux_audit_source: /var/log/audit/audit.log +validate_selinux_skip_list_dest: "{{ validate_selinux_working_dir }}/denials-skip-list.txt" +validate_selinux_filtered_denials_dest: "{{ validate_selinux_working_dir }}/denials-filtered.log" +validate_selinux_strict: false +validate_selinux_filter: "None" +validate_selinux_skip_list: {} diff --git a/roles/validate_selinux/handlers/main.yml b/roles/validate_selinux/handlers/main.yml new file mode 100644 index 0000000..dfd4c73 --- /dev/null +++ b/roles/validate_selinux/handlers/main.yml @@ -0,0 +1,15 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. diff --git a/roles/validate_selinux/molecule/default/Dockerfile b/roles/validate_selinux/molecule/default/Dockerfile new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/validate_selinux/molecule/default/Dockerfile @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/validate_selinux/molecule/default/molecule.yml b/roles/validate_selinux/molecule/default/molecule.yml new file mode 100644 index 0000000..1dbdf89 --- /dev/null +++ b/roles/validate_selinux/molecule/default/molecule.yml @@ -0,0 +1,49 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + dockerfile: Dockerfile + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + dockerfile: Dockerfile + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_LIBRARY: "../../../../library" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/validate_selinux/molecule/default/playbook.yml b/roles/validate_selinux/molecule/default/playbook.yml new file mode 100644 index 0000000..00c31d7 --- /dev/null +++ b/roles/validate_selinux/molecule/default/playbook.yml @@ -0,0 +1,63 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + gather_facts: false + vars: + validate_selinux_working_dir: '/tmp' + + tasks: + - name: Simple run without filter against clean auditlog + include_role: + name: validate_selinux + vars: + validate_selinux_audit_source: '/var/log/audit-clean.log' + + - name: Run with filter against unclean auditlog + include_role: + name: validate_selinux + vars: + validate_selinux_audit_source: '/var/log/audit-unclean.log' + validate_selinux_skip_list: + - entry: 'tcontext=system_u:system_r:init_t' + comment: 'This one is a real-life entry' + - entry: 'tcontext=system_u:system_r:system_dbusd_t' + comment: 'This one is another real-life entry' + + - name: Run without filter against unclean auditlog + block: + - name: Run role + include_role: + name: validate_selinux + vars: + validate_selinux_audit_source: '/var/log/audit-unclean.log' + validate_selinux_strict: true + rescue: + - name: Clear host error + meta: clear_host_errors + + - name: Status message + debug: + msg: 'Successfully detected denials issue!' + + - name: End play + meta: end_play + + - name: Fail if we get to this place + fail: + msg: 'Unit test failed: did not detect untracked denials!' diff --git a/roles/validate_selinux/molecule/default/prepare.yml b/roles/validate_selinux/molecule/default/prepare.yml new file mode 100644 index 0000000..6d8f478 --- /dev/null +++ b/roles/validate_selinux/molecule/default/prepare.yml @@ -0,0 +1,60 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Prepare + hosts: all + gather_facts: false + + tasks: + - name: Populate fake clean auditlog + copy: + dest: /var/log/audit-clean.log + owner: root + mode: 0600 + group: root + # yamllint disable rule:line-length + content: | + type=SERVICE_START msg=audit(1575877870.934:286): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=sssd-kcm comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=SERVICE_STOP msg=audit(1575878320.981:287): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=sssd-kcm comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=USER_ACCT msg=audit(1575878471.739:288): pid=4430 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=USER_CMD msg=audit(1575878471.740:289): pid=4430 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='cwd="/root" cmd=626F7267202D2D696E666F20637265617465202D2D636F6D7072657373696F6E206C7A34202D2D6578636C7564652D636163686573202D2D6578636C756465202A2F2A2E6C6F636B202D2D6578636C756465202A2F2E746F78202D2D6578636C756465202A2F2E737465737472202D2D6578636C756465202A2F727562792D76656E646F72202D2D6578636C756465202A2F7A75756C2F202D2D6578636C756465202A2F73736866732F202D2D6578636C756465202A2F2E6C6F63616C2F7368617265202F6D656469612F6261636B7570732F7268656C3A3A31306130393963382D316135612D313165612D613663622D386331363435366466626265202F686F6D652F636A65616E6E6572 exe="/usr/bin/sudo" terminal=? res=success'UID="root" AUID="unset" + type=USER_ACCT msg=audit(1575878554.296:294): pid=4445 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=USER_CMD msg=audit(1575878554.296:295): pid=4445 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='cwd="/root" cmd=626F7267206C697374202F6D656469612F6261636B7570732F7268656C exe="/usr/bin/sudo" terminal=? res=success'UID="root" AUID="unset" + type=USER_ACCT msg=audit(1575878555.032:300): pid=4449 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='op=PAM:accounting grantors=pam_unix,pam_localuser acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=USER_CMD msg=audit(1575878555.032:301): pid=4449 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 msg='cwd="/root" cmd=626F7267207072756E65202D70202D2D6B6565702D77697468696E203277202D2D7374617473202F6D656469612F6261636B7570732F7268656C exe="/usr/bin/sudo" terminal=? res=success'UID="root" AUID="unset" + type=SERVICE_START msg=audit(1575878869.915:306): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=fprintd comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + type=SERVICE_STOP msg=audit(1575878900.615:312): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=fprintd comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset" + + # yamllint enable rule:line-length + - name: Populate unclean auditlog + copy: + dest: /var/log/audit-unclean.log + owner: root + mode: 0600 + group: root + # yamllint disable rule:line-length + content: | + type=AVC msg=audit(1575534183.234:4933): avc: denied { write } for pid=11266 comm="iptables" path="pipe:[231496]" dev="pipefs" ino=231496 scontext=system_u:system_r:iptables_t:s0 tcontext=system_u:system_r:certmonger_t:s0 tclass=fifo_file permissive=1 + type=AVC msg=audit(1575534183.342:4934): avc: denied { write } for pid=11284 comm="iptables" path="pipe:[231496]" dev="pipefs" ino=231496 scontext=system_u:system_r:iptables_t:s0 tcontext=system_u:system_r:certmonger_t:s0 tclass=fifo_file permissive=1 + type=USER_AVC msg=audit(1575535009.861:5275): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.DBus member=Hello dest=org.freedesktop.DBus spid=38869 scontext=system_u:system_r:container_t:s0:c313,c573 tcontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535009.861:5276): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.systemd1.Manager member=GetDynamicUsers dest=org.freedesktop.systemd1 spid=38869 tpid=1 scontext=system_u:system_r:container_t:s0:c313,c573 tcontext=system_u:system_r:init_t:s0 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535009.862:5277): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_return dest=:1.1198 spid=1 tpid=38869 scontext=system_u:system_r:init_t:s0 tcontext=system_u:system_r:container_t:s0:c313,c573 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535013.340:5290): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.DBus member=Hello dest=org.freedesktop.DBus spid=39132 scontext=system_u:system_r:container_t:s0:c192,c917 tcontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535013.341:5291): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.systemd1.Manager member=GetDynamicUsers dest=org.freedesktop.systemd1 spid=39132 tpid=1 scontext=system_u:system_r:container_t:s0:c192,c917 tcontext=system_u:system_r:init_t:s0 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535013.342:5292): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_return dest=:1.1209 spid=1 tpid=39132 scontext=system_u:system_r:init_t:s0 tcontext=system_u:system_r:container_t:s0:c192,c917 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535028.912:5307): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.DBus member=Hello dest=org.freedesktop.DBus spid=39430 scontext=system_u:system_r:container_t:s0:c776,c848 tcontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" + type=USER_AVC msg=audit(1575535028.913:5308): pid=1397 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_call interface=org.freedesktop.systemd1.Manager member=GetDynamicUsers dest=org.freedesktop.systemd1 spid=39430 tpid=1 scontext=system_u:system_r:container_t:s0:c776,c848 tcontext=system_u:system_r:init_t:s0 tclass=dbus permissive=1 exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'UID="dbus" AUID="unset" SAUID="dbus" diff --git a/roles/validate_selinux/molecule/default/verify.yml b/roles/validate_selinux/molecule/default/verify.yml new file mode 100644 index 0000000..dfd4c73 --- /dev/null +++ b/roles/validate_selinux/molecule/default/verify.yml @@ -0,0 +1,15 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. diff --git a/roles/validate_selinux/tasks/main.yml b/roles/validate_selinux/tasks/main.yml new file mode 100644 index 0000000..d0ef3a0 --- /dev/null +++ b/roles/validate_selinux/tasks/main.yml @@ -0,0 +1,123 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +# "validate-selinux" tasks + +- name: "Ensure {{ validate_selinux_audit_source }} does exist" + become: true + stat: + path: "{{ validate_selinux_audit_source }}" + register: auditlog_stat + +- name: "Fail if {{ validate_selinux_audit_source }} does not exit" + when: not auditlog_stat.stat.exists + fail: + msg: "ERROR: {{ validate_selinux_audit_source }} does not exist!" + +- name: Load skip list from provided file + when: + - validate_selinux_filter != 'None' + - validate_selinux_skip_list is not defined + include_vars: "{{ validate_selinux_filter }}" + +- name: Gather subset of facts + setup: + gather_subset: "!min,distribution_major_version" + when: + - validate_selinux_filter == 'None' + - validate_selinux_skip_list is not defined + - ansible_distribution_major_version is not defined + +- name: Load skip list variables (undercloud or overcloud) + when: + - validate_selinux_skip_list is not defined + include_vars: "{{ lookup('first_found', lookhere, errors='ignore') }}" + vars: + lookhere: + - "selinux_skip_{{ release }}_on_{{ ansible_distribution_major_version }}.yml" + - "selinux_skip_{{ release }}.yml" + +- name: Fetch denials from auditlog + become: true + ignore_errors: true + changed_when: false + shell: | + set -o pipefail + grep denied {{ validate_selinux_audit_source }} > /tmp/denials.log + +- name: Get stat for denials.log + stat: + path: /tmp/denials.log + register: denials_log + +- name: Everything is fine + when: denials_log.stat.size == 0 + debug: + msg: "No untracked SELinux AVC detected, congratulations!" + +- name: Next steps only if we have denials + when: denials_log.stat.size > 0 + block: + - name: Create skip list + when: validate_selinux_skip_list != {} + template: + src: skip-list.j2 + dest: "{{ validate_selinux_skip_list_dest }}" + mode: 0644 + + - name: Filter out denials + when: validate_selinux_skip_list != {} + ignore_errors: true + changed_when: false + shell: | + set -o pipefail + grep -v -f {{ validate_selinux_skip_list_dest }} /tmp/denials.log > {{ validate_selinux_filtered_denials_dest }} + + - name: No skip_list + when: validate_selinux_skip_list == {} + copy: + remote_src: true + src: /tmp/denials.log + dest: "{{ validate_selinux_filtered_denials_dest }}" + + - name: Get stat for filtered denials + stat: + path: "{{ validate_selinux_filtered_denials_dest }}" + register: denials_stat + + - name: debug + debug: + var: denials_stat + + - name: Fail if we found untracked denials + when: + - validate_selinux_strict|bool + - denials_stat.stat.size != 0 + fail: + msg: "Untracked SELinux AVCs found, please refer to {{ validate_selinux_filtered_denials_dest }}" + + - name: Output information in case we do not fail + when: + - not validate_selinux_strict|bool + - denials_stat.stat.size != 0 + debug: + msg: "Untracked SELinux AVCs found, please refer to {{ validate_selinux_filtered_denials_dest }}" + + - name: Output information if everything is fine + when: denials_stat.stat.size == 0 + debug: + msg: "No untracked SELinux AVC detected, congratulations!" diff --git a/roles/validate_selinux/templates/skip-list.j2 b/roles/validate_selinux/templates/skip-list.j2 new file mode 100644 index 0000000..4409f3e --- /dev/null +++ b/roles/validate_selinux/templates/skip-list.j2 @@ -0,0 +1,3 @@ +{% for entry in validate_selinux_skip_list %} +{{ entry.entry }} +{% endfor %} diff --git a/roles/validate_selinux/vars/main.yml b/roles/validate_selinux/vars/main.yml new file mode 100644 index 0000000..d826fe1 --- /dev/null +++ b/roles/validate_selinux/vars/main.yml @@ -0,0 +1,22 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +# While options found within the vars/ path can be overridden using extra +# vars, items within this path are considered part of the role and not +# intended to be modified. + +# All variables within this role should have a prefix of "validate_selinux" diff --git a/roles/xfs_check_ftype/molecule/default/Dockerfile.j2 b/roles/xfs_check_ftype/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..1b91a0e --- /dev/null +++ b/roles/xfs_check_ftype/molecule/default/Dockerfile.j2 @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["sh", "-c", "while true; do sleep 10000; done"] diff --git a/roles/xfs_check_ftype/molecule/default/molecule.yml b/roles/xfs_check_ftype/molecule/default/molecule.yml new file mode 100644 index 0000000..13d65f6 --- /dev/null +++ b/roles/xfs_check_ftype/molecule/default/molecule.yml @@ -0,0 +1,48 @@ +--- +driver: + name: docker + +log: true + +platforms: + - name: centos7 + hostname: centos7 + image: centos:7 + privileged: true + pkg_extras: python-setuptools + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + + - name: fedora28 + hostname: fedora28 + image: fedora:28 + privileged: true + pkg_extras: python*-setuptools + environment: + <<: *env + +provisioner: + name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + +lint: + enabled: false + +verifier: + name: testinfra + lint: + name: flake8 diff --git a/roles/xfs_check_ftype/molecule/default/playbook.yml b/roles/xfs_check_ftype/molecule/default/playbook.yml new file mode 100644 index 0000000..4c7f853 --- /dev/null +++ b/roles/xfs_check_ftype/molecule/default/playbook.yml @@ -0,0 +1,21 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Converge + hosts: all + roles: + - role: xfs_check_ftype diff --git a/roles/xfs_check_ftype/molecule/default/prepare.yml b/roles/xfs_check_ftype/molecule/default/prepare.yml new file mode 100644 index 0000000..822f32b --- /dev/null +++ b/roles/xfs_check_ftype/molecule/default/prepare.yml @@ -0,0 +1,60 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +- name: Prepare + hosts: all + + vars: + xfs_image_file: "/root/xfs_{{ ansible_distribution|lower }}.img" + + post_tasks: + - name: Create a blank image + command: "dd if=/dev/zero of={{ xfs_image_file }} bs=1M count=50" + tags: + - skip_ansible_lint + + - name: Install tools for managing XFS partitions + package: + name: "{{ item }}" + state: present + loop: + - parted + - xfsprogs + + - name: Map the partition file to the loop device + command: "losetup --find --show {{ xfs_image_file }}" + register: losetup + tags: + - skip_ansible_lint + + - name: Format the partition with XFS with ftype=1 + filesystem: + fstype: xfs + dev: "{{ losetup.stdout }}" + opts: -n ftype=1 + + - name: Create a directory for the partition to mount onto + file: + path: /xfs + state: directory + + - name: Mount the XFS partition + mount: + path: /xfs + src: "{{ losetup.stdout }}p1" + fstype: xfs + state: present diff --git a/roles/xfs_check_ftype/molecule/default/verify.yml b/roles/xfs_check_ftype/molecule/default/verify.yml new file mode 100644 index 0000000..dfd4c73 --- /dev/null +++ b/roles/xfs_check_ftype/molecule/default/verify.yml @@ -0,0 +1,15 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. diff --git a/roles/xfs_check_ftype/tasks/main.yml b/roles/xfs_check_ftype/tasks/main.yml new file mode 100644 index 0000000..4775676 --- /dev/null +++ b/roles/xfs_check_ftype/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: Check if there are XFS volumes with ftype=0 + become: true + shell: | + for dev in $(df -h | grep '/dev/' | grep -v 'tmp' | cut -d' ' -f1) + do + parseftype=$(xfs_info $dev | grep ftype=0); + if [[ ! -z "$parseftype" ]]; then + ftype="ftype=0"; + break; + fi + done + echo $ftype; + register: ftype + changed_when: false + +- name: Check ftype + fail: + msg: > + XFS volumes formatted using ftype=0 are incompatible + with the docker overlayfs driver. + Run xfs_info on {{ ansible_fqdn }} and fix those volumes + before proceeding with the upgrade. + when: + - ftype.stdout == 'ftype=0' diff --git a/roles/xfs_check_ftype/vars/main.yml b/roles/xfs_check_ftype/vars/main.yml new file mode 100644 index 0000000..79d8c7f --- /dev/null +++ b/roles/xfs_check_ftype/vars/main.yml @@ -0,0 +1,8 @@ +--- +metadata: + name: XFS ftype check + description: > + Check if there is at least 1 XFS volume + with ftype=0 in any deployed node. + groups: + - pre-upgrade diff --git a/validations_common/tests/library/test_validations_read_ini.py b/validations_common/tests/library/test_validations_read_ini.py new file mode 100644 index 0000000..b699567 --- /dev/null +++ b/validations_common/tests/library/test_validations_read_ini.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- + +# 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. + +""" +test_validations_read_ini +---------------------------------- + +Tests for `validations_read_ini` module. +""" + + +import os +import tempfile + +import library.validations_read_ini as validation +from validations_common.tests import base + + +invalid_content = ''' +[DEFAULT# + hello = +''' + +valid_content = ''' +[DEFAULT] +debug=True + +[dhcp] +dhcp_start=192.168.0.1 +dhcp_end=192.168.0.254 + +[secrets] +password=1234 +''' + + +class TestValidationsReadIni(base.TestCase): + + def test_check_file_invalid_path(self): + '''Test validations_read_ini when path is invalid''' + + msg = validation.check_file('non/existing/path', False) + self.assertEqual("Could not open the ini file: 'non/existing/path'", + msg) + + def test_check_file_ignore_missing(self): + '''Test validations_read_ini when ignoring missing files''' + + msg = validation.check_file('non/existing/path', True) + self.assertEqual("Could not open the ini file: 'non/existing/path'", + msg) + + def test_check_file_valid_path(self): + '''Test validations_read_ini when path is valid''' + + tmpfile = self.create_tmp_ini() + tmp_name = os.path.relpath(tmpfile.name) + msg = validation.check_file(tmp_name, False) + tmpfile.close() + + self.assertEqual('', msg) + + def test_get_result_invalid_format(self): + '''Test validations_read_ini when file format is valid''' + + tmpfile = self.create_tmp_ini() + tmp_name = os.path.relpath(tmpfile.name) + tmpfile.write(invalid_content.encode('utf-8')) + tmpfile.seek(0) + ret, msg, value = validation.get_result(tmp_name, 'section', 'key') + tmpfile.close() + + self.assertEqual(validation.ReturnValue.INVALID_FORMAT, ret) + self.assertEqual("The file '{}' is not in a valid INI format.".format( + tmp_name), msg) + self.assertIsNone(value) + + def test_get_result_key_not_found(self): + '''Test validations_read_ini when key is not found''' + + tmpfile = self.create_tmp_ini() + tmp_name = os.path.relpath(tmpfile.name) + tmpfile.write(valid_content.encode('utf-8')) + tmpfile.seek(0) + ret, msg, value = validation.get_result(tmp_name, 'section', 'key') + tmpfile.close() + + self.assertEqual(validation.ReturnValue.KEY_NOT_FOUND, ret) + self.assertEqual(("There is no key 'key' under the section 'section' " + "in file {}.").format(tmp_name), msg) + self.assertIsNone(value) + + def test_get_result_key_not_found_with_default(self): + '''Test validations_read_ini when key is not found but has a default''' + + tmpfile = self.create_tmp_ini() + tmp_name = os.path.relpath(tmpfile.name) + tmpfile.write(valid_content.encode('utf-8')) + tmpfile.seek(0) + ret, msg, value = validation.get_result(tmp_name, 'section', 'key', + 'foo') + tmpfile.close() + + self.assertEqual(validation.ReturnValue.OK, ret) + self.assertEqual(("There is no key 'key' under section 'section' " + "in file {}. Using default value '{}'" + ).format(tmp_name, 'foo'), msg) + self.assertEqual(value, 'foo') + + def test_get_result_ok(self): + '''Test validations_read_ini when key is not found''' + + tmpfile = self.create_tmp_ini() + tmp_name = os.path.relpath(tmpfile.name) + tmpfile.write(valid_content.encode('utf-8')) + tmpfile.seek(0) + ret, msg, value = validation.get_result(tmp_name, 'secrets', + 'password') + tmpfile.close() + + self.assertEqual(validation.ReturnValue.OK, ret) + self.assertEqual(("The key 'password' under the section 'secrets'" + " in file {} has the value: '1234'").format( + tmp_name), msg) + self.assertEqual('1234', value) + + def create_tmp_ini(self): + '''Create temporary tmp.ini file, return its full name''' + + path = 'validations_common/tests' + tmpfile = tempfile.NamedTemporaryFile(suffix='.ini', prefix='tmp', + dir=path) + return tmpfile