From ba82da911f4c26607c13302cc147a03b8f35943e Mon Sep 17 00:00:00 2001 From: llesniax Date: Mon, 8 May 2023 14:30:30 +0200 Subject: [PATCH 1/2] common: files for automatic platform configuration using Ansible --- utils/ansible/README | 6 - utils/ansible/README.md | 64 ++++++ utils/ansible/configure-pmem.yml | 120 ++++++++++ utils/ansible/library/env.py | 337 ++++++++++++++++++++++++++++ utils/ansible/opensuse-setup.yml | 178 +++++++++++++++ utils/ansible/rockylinux9-setup.yml | 157 +++++++++++++ 6 files changed, 856 insertions(+), 6 deletions(-) delete mode 100644 utils/ansible/README create mode 100644 utils/ansible/README.md create mode 100644 utils/ansible/configure-pmem.yml create mode 100644 utils/ansible/library/env.py create mode 100644 utils/ansible/opensuse-setup.yml create mode 100644 utils/ansible/rockylinux9-setup.yml diff --git a/utils/ansible/README b/utils/ansible/README deleted file mode 100644 index ddcb3cc42d2..00000000000 --- a/utils/ansible/README +++ /dev/null @@ -1,6 +0,0 @@ -Persistent Memory Development Kit - -This is utils/ansible/README. - -The scripts in this directory allow you to set up an RockyLinux and OpenSuSe -environment on a real HW and build a PMDK project in it. diff --git a/utils/ansible/README.md b/utils/ansible/README.md new file mode 100644 index 00000000000..d6d42a32391 --- /dev/null +++ b/utils/ansible/README.md @@ -0,0 +1,64 @@ +Persistent Memory Development Kit + +This is utils/ansible/README. + +The scripts in this directory allow you to set up an RockyLinux and OpenSuSe + +environment on a real HW and build a PMDK project in it. + +To use playbooks it is required to install Ansible first. It must be done on computer that will be + used to execute script, not on target platform. + +Commands: + +``` +ansible-playbook -i , opensuse-setup.yml --extra-vars + "host=all ansible_user=root ansible_password= testUser=pmdkuser" + ``` + +``` +ansible-playbook -i , rockylinux-setup.yml --extra-vars + "host=all ansible_user=root ansible_password= testUser=pmdkuser" + ``` + +Those commands above will install the required packages to build PMDK tests. + +``` +ansible-playbook -i , configure-pmem.yml --extra-vars + "host=all ansible_user=root ansible_password= testUser=pmdkuser" + ``` + +This command will configure regions and namespaces on DIMMs. + +NOTE: + +- If platform does not have DIMM's regions configured earlier you can add additional var for + configureProvisioning.yml playbook: newRegions=true eg. + +``` +ansible-playbook -i , configureProvisioning.yml --extra-vars + "host=all ansible_user=root ansible_password= newRegions=true testUser=pmdkuser" + ``` + +This will reboot the platform. + +Configured regions are required to create namespaces on the DIMMs. + +- If Linux kernel is outdated, opensuseAnsible and rockyAnsible playbooks will reboot target platform. + +- It is possible to run playbooks inside target platform but if notes above occurs then you need to rerun this playbook. + +To run playbooks inside the platform please comment line: + +` - hosts: "{{ host }}"` + +and uncomment + +``` +# - hosts: localhost +# connection: local +``` + +and run with example command + +`sudo ansible-playbook opensuse-setup.yml --extra-vars "testUser=pmdkuser"` diff --git a/utils/ansible/configure-pmem.yml b/utils/ansible/configure-pmem.yml new file mode 100644 index 00000000000..418579c348a --- /dev/null +++ b/utils/ansible/configure-pmem.yml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2023, Intel Corporation + +# This playbook is designed to configure regions and namespaces on DIMMs so user can execute +# tests later. Playbook usage is described in README.md file. +# Steps below are divided into 3 parts: removing previous namespaces (if existed), creating new regions +# (if requested by the user) and creating namespaces on that regions. +# +# Shell script implemented in this playbook for namespace creation will create 9 DAX namespaces with aligned sizes +# to fit first region and 1 FSDAX namespace to fit second region. It is assumed that system contains 2 interleaved regions +# beforehand. Setting "newRegions" to "true" will do that. + +- hosts: "{{ host }}" +# - hosts: localhost +# connection: local + vars: + newRegions: false + testUser: pmdkuser + + tasks: + - name: "Test if ndctl is installed" + shell: which ndctl + + - name: "Unmount namespaces if they exist" + shell: sudo umount /dev/pmem* || true + + - name: "Destroy current namespaces" + shell: | + sudo ndctl disable-namespace all + sudo ndctl destroy-namespace all + register: namespaces + + - debug: var=namespaces + + - name: "Create new regions" + block: + - name: "Test if ipmctl is installed" + shell: which ipmctl + + - name: "Create goal in AppDirectInterleaved mode" + shell: ipmctl create -f -goal + + - name: "Reboot machine in order to apply new AppDirectInterleaved goal" + reboot: + when: newRegions == 'true' + + - name: "Create new namespace configuration" + shell: | + #!/usr/bin/env bash + DEV_DAX_R=0x0000 + FS_DAX_R=0x0001 + MOUNT_POINT="/mnt/pmem0" + + function check_alignment() { + local size=$1 + local interleave_width=$(sudo ipmctl show -dimm -socket 1 | grep "0x1" | wc -l) + local size_alignment=$(expr $size % $interleave_width) + + if [ "$size_alignment" -gt "0" ]; then + size=$(expr $size - $size_alignment + $interleave_width) + fi + + echo "${size}G" + } + + function create_devdax() { + local align=$1 + local size=$2 + local size_option="-s $size" + + if [ -z "$size" ]; then + size_option="" + fi + + local cmd="sudo ndctl create-namespace --mode devdax -a ${align} ${size_option} -r ${DEV_DAX_R} -f" + result=$(${cmd}) + if [ $? -ne 0 ]; then + exit 1; + fi + } + + function create_fsdax() { + local cmd="sudo ndctl create-namespace --mode fsdax -r ${FS_DAX_R} -f" + result=$(${cmd}) + if [ $? -ne 0 ]; then + exit 1; + fi + jq -r '.blockdev' <<< $result + } + + BIG_NS_SIZE=$(check_alignment 55) + SMALL_NS_SIZE=$(check_alignment 4) + + create_devdax 4k $SMALL_NS_SIZE + create_devdax 4k $SMALL_NS_SIZE + create_devdax 2m $SMALL_NS_SIZE + create_devdax 2m $SMALL_NS_SIZE + create_devdax 4k $BIG_NS_SIZE + create_devdax 4k $BIG_NS_SIZE + create_devdax 2m $BIG_NS_SIZE + create_devdax 2m $BIG_NS_SIZE + create_devdax 2m $SMALL_NS_SIZE + + pmem_name=$(create_fsdax) + + if [ ! -d "${MOUNT_POINT}" ]; then + sudo mkdir ${MOUNT_POINT} + fi + + sudo mkfs.ext4 -F /dev/${pmem_name} + sudo mount -o dax /dev/${pmem_name} ${MOUNT_POINT} + sudo chown -R {{ testUser }} ${MOUNT_POINT} + + sudo chmod 777 /dev/dax* || true + sudo chmod a+rw /sys/bus/nd/devices/region*/deep_flush + sudo chmod +r /sys/bus/nd/devices/ndbus*/region*/resource + sudo chmod +r /sys/bus/nd/devices/ndbus*/region*/dax*/resource + register: script + + - debug: var=script diff --git a/utils/ansible/library/env.py b/utils/ansible/library/env.py new file mode 100644 index 00000000000..05dd3302207 --- /dev/null +++ b/utils/ansible/library/env.py @@ -0,0 +1,337 @@ +#!/usr/bin/python + +# +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2019-2023, Intel Corporation +# + +import os +from ansible.module_utils.basic import AnsibleModule + +DOCUMENTATION = ''' +--- +module: env + +short_description: Module for managing environmental variables on remote hosts + +description: + - "Module for set and unset environmental variables on remote hosts. + Setting is done by writing export definitions to the file* (this should help with keeping persistence of values + between reboots) and then execute 'source' command (in order to feed current session with exported variables). + + - ---- + - * file: the file under the care of this module, specified by 'path' parameter. By default it is a file in + /etc/profile.d/" + +options: + name: + description: + - This is the name of the variable to manage + required: true + value: + description: + - This is the value of the variable to manage. If 'state'='present', this option is required. + required: false + state: + description: + - If 'present', ensure that given variable is set to given value. This is the default. + required: false + default: present + choices: [ present ] + path: + description: + - This is the path of a file where export definitions will be written. Usually you don't want to change it. + required: false + default: /etc/profile.d/ansible_env_module_definitions.sh + +author: + - dpysx +''' + +EXAMPLES = ''' +# Set http_proxy: +- name: set http proxy + env: + name: http_proxy + value: http://example.com:80 +''' + +RETURN = ''' +old_value: + description: Value of variable, before the module was called. + type: str +''' + + +# ####################################################################################### +# ########################## General helpers ########################################## +# ####################################################################################### + + +def check_prerequisites(module, result): + """Check if passed module and result are valid types from AnsibleModule.""" + if not isinstance(module, AnsibleModule): + raise TypeError("Given module is not valid!") + + if not isinstance(result, dict): + raise TypeError("Given result is not valid!") + + +# ####################################################################################### +# ################### Helpers for dealing with system commands ######################## +# ####################################################################################### + + +def escape_quotes(string): + """Escape every double quote char with a backslash.""" + return string.replace('"', '\\"') + + +def run_command(module, result, command): + """Execute command and return its stdout; when status not zero, fail module execution.""" + check_prerequisites(module, result) + + command = 'bash -lc "' + escape_quotes(command) + '"' + + rc, stdout, stderr = module.run_command(command) + + if rc != 0: + fail_message = "Command '" + command + "' failed with status code " + str( + rc) + ", stdout: '" + stdout + "', stderr: '" + stderr + "'." + module.fail_json(msg=fail_message, **result) + + return stdout + + +# ####################################################################################### +# ###################### Helpers for handling checking env vars ####################### +# ####################################################################################### + + +def get_env_value_or_empty(module, result, name): + """Obtain value of variable and return it; if not present, return empty string.""" + check_prerequisites(module, result) + + print_variable = 'echo "$' + name + '"' + variable_value = run_command(module, result, print_variable) + + return variable_value.replace('\n', '') + + +def is_env_present(module, result, name): + """Check if variable with given name is present in system.""" + check_prerequisites(module, result) + + env_value = get_env_value_or_empty(module, result, name) + if env_value == "": + return False + else: + return True + + +# ####################################################################################### +# ########################## Helpers for file handling ################################ +# ####################################################################################### + + +valid_shebang = "#!/usr/bin/env bash\n" + + +def read_file_lines(module, result, filename): + """Read file and return its lines in a form of list.""" + content = [] + try: + file = open(filename, "r") + content = file.readlines() + file.close() + except IOError: + fail_message = "Cannot open file '" + filename + "' for reading." + module.fail_json(msg=fail_message, **result) + + return content + + +def is_valid_shebang(module, result, filename): + """Check if file has valid, bash shebang line.""" + check_prerequisites(module, result) + + file_lines = read_file_lines(module, result, filename) + + global valid_shebang + if len(file_lines) == 0 or file_lines[0] != valid_shebang: + return False + else: + return True + + +def write_file_lines(module, result, filename, lines): + """Write all lines to the file.""" + check_prerequisites(module, result) + + changed = False + if not os.access(filename, os.F_OK): + changed = True + + try: + file = open(filename, 'w') + except IOError: + fail_message = "Cannot open file '" + filename + "' for write." + module.fail_json(msg=fail_message, **result) + + try: + content = [] + for line in lines: + if not line.endswith('\n'): + s = line + "\n" + else: + s = line + content.append(s) + + file.writelines(content) + changed = True + except: + fail_message = "Cannot write to file '" + filename + "'." + module.fail_json(msg=fail_message, **result) + finally: + file.close() + + result['changed'] = changed + + +def write_variable_to_file(module, result, name, value, filename): + """Write export definition of the variable to the file. Removes possible duplicates.""" + check_prerequisites(module, result) + global valid_shebang + + content = [] + env_entry_start = "export " + name + "=" + env_entry = env_entry_start + '"' + escape_quotes(value) + '"\n' + + if os.access(filename, os.F_OK): + content = read_file_lines(module, result, filename) + + if not is_valid_shebang(module, result, filename): + content.insert(0, valid_shebang) + + # remove all entries for current variable: + filtered_content = [] + for line in content: + if not line.startswith(env_entry_start): + filtered_content.append(line) + + content = filtered_content + content.append(env_entry) + + write_file_lines(module, result, filename, content) + result['changed'] = True + + else: + content.append(valid_shebang) + content.append(env_entry) + write_file_lines(module, result, filename, content) + try: + os.chmod(filename, 0o755) + result['changed'] = True + except: + fail_message = "Cannot change file '" + filename + "' permissions to 755." + module.fail_json(msg=fail_message, **result) + + +# ####################################################################################### +# ############### Helpers for exporting / unset vars to current session ############### +# ####################################################################################### + + +def import_variables_from_file(module, result, filename): + """Execute 'source' command with file parameter in order to import definitions to the current session.""" + check_prerequisites(module, result) + + result['changed'] = True + + load_variables_from_file = 'source "' + filename + '"' + run_command(module, result, load_variables_from_file) + + +def export_variable(module, result, name, value): + """Execute 'export' command in order to add exported definition.""" + check_prerequisites(module, result) + + result['changed'] = True + export_var = "export " + name + '="' + escape_quotes(value) + '"' + run_command(module, result, export_var) + + +# ####################################################################################### +# ########################## Main module functions #################################### +# ####################################################################################### + + +def present_flow(module, result, name, value, filename): + """Execute module flow for 'present' module mode.""" + check_prerequisites(module, result) + + current_value = get_env_value_or_empty(module, result, name) + result['old_value'] = current_value + + if value is not None: + + if is_env_present(module, result, name) and current_value == value: + module.exit_json(**result) + + result['changed'] = True + + if not module.check_mode: + write_variable_to_file(module, result, name, value, filename) + import_variables_from_file(module, result, filename) + export_variable(module, result, name, value) + + module.exit_json(**result) + + else: + if is_env_present(module, result, name): + module.exit_json(**result) + else: + module.fail_json("variable is not set!", **result) + + +def run_module(): + """Prepare parameter and return value object, select and execute proper module flow.""" + + module_args = dict( + state=dict(type='str', default='present', choices=['present']), + path=dict(type='str', default='/etc/profile.d/ansible_env_module_definitions.sh'), + name=dict(type='str', required=True), + value=dict(type='str'), + ) + + result = dict( + changed=False, + old_value='' + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + # state = module.params['state'] + name = module.params['name'] + value = module.params['value'] + path = module.params['path'] + + # arguments' reasonableness check + if value is None: + module.fail_json(msg="There should be 'value' set as well!", **result) + + present_flow(module, result, name, value, path) + + # flow functions should end module's execution; when otherwise, there is some ancient evil in here: + module.fail_json(msg="Unexpected execution path, this is a bug in this module!", **result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/utils/ansible/opensuse-setup.yml b/utils/ansible/opensuse-setup.yml new file mode 100644 index 00000000000..5a431b97221 --- /dev/null +++ b/utils/ansible/opensuse-setup.yml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2023, Intel Corporation + +# This playbook is designed to install all required packages and configure openSUSE to execute tests. +# Playbook description and how to use it is available in README.md file + +- hosts: "{{ host }}" +# - hosts: localhost +# connection: local + vars: + testUser: pmdkuser + + tasks: + + - name: "Update kernel packages" + package: + name: "kernel-default" + state: latest + register: isUpdated + + - name: "Update OS packages" + package: + name: "*" + state: latest + + - name: "Reboot platform to apply updates" + reboot: + when: isUpdated.changed + + - name: "Add permanent pkg config variable to the system" + env: + state: present + name: PKG_CONFIG_PATH + value: /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig + + - name: "Add permanent ld library path to the system" + env: + state: present + name: LD_LIBRARY_PATH + value: /usr/lib64:/usr/lib + + - name: "Add openSUSE Leap 15.4 Oss repo" + zypper_repository: + name: oss + repo: 'http://download.opensuse.org/distribution/leap/15.4/repo/oss' + state: present + + - name: "Install VALGRIND deps" + package: + state: present + name: + - autoconf + - automake + - file + - findutils + - git + + - name: "Install PMDK base deps" + package: + state: present + name: + - cmake + - gcc + - gcc-c++ + - git + - make + - pkgconfig + - systemd + + - name: "Install benchmarks deps (optional)" + package: + state: present + name: + - glib2-devel + + - name: "Install examples deps (optional)" + package: + state: present + name: + - fuse + - fuse-devel + - ncurses-devel + - libuv-devel + + - name: "Install documentation deps (optional)" + package: + state: present + name: + - pandoc + + - name: "Install tests deps" + package: + state: present + name: + - bc + - gdb + - libunwind-devel + - strace + + - name: "Install packaging deps" + package: + state: present + name: + - rpm-build + - rpmdevtools + + - name: "Install miscellaneous deps" + package: + state: present + name: + - clang + - hub + - lbzip2 + - man + - python3-flake8 + - rsync + - sudo + - tar + - which + - xmlto + + - name: "Install NDCTL deps" + package: + state: present + name: + - bash-completion-devel + - keyutils-devel + - libjson-c-devel + - libkmod-devel + - libtool + - libudev-devel + - libuuid-devel + - systemd-devel + + - name: "Run the install-valgrind script with arguments" + script: ../docker/images/install-valgrind.sh fedora + + - name: "Run the install-libndctl script with arguments" + script: ../docker/images/install-libndctl.sh tags/v70.1 + + - name: "Add new user" + shell: | + #!/usr/bin/env bash + export USER={{ testUser }} + export USERPASS=pmdkpass + useradd -m $USER + export PFILE=./password + echo $USERPASS > $PFILE + echo $USERPASS >> $PFILE + passwd $USER < $PFILE + rm -f $PFILE + sed -i 's/# %wheel/%wheel/g' /etc/sudoers + groupadd wheel + gpasswd wheel -a $USER + + - name: "Set variable OS" + env: + state: present + name: 'OS' + value: 'opensuse/leap' + + - name: "Set variable OS_VER" + env: + state: present + name: 'OS_VER' + value: '15' + + - name: "Set variable PACKAGE_MANAGER" + env: + state: present + name: 'PACKAGE_MANAGER' + value: 'rpm' + + - name: "Set variable NOTTY" + env: + state: present + name: 'NOTTY' + value: '1' diff --git a/utils/ansible/rockylinux9-setup.yml b/utils/ansible/rockylinux9-setup.yml new file mode 100644 index 00000000000..b032664cc0d --- /dev/null +++ b/utils/ansible/rockylinux9-setup.yml @@ -0,0 +1,157 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2023, Intel Corporation + +# This playbook is designed to install all required packages and configure Rocky Linux 9 to execute tests. +# Playbook description and how to use it is available in README.md file + +- hosts: "{{ host }}" +# - hosts: localhost +# connection: local + vars: + testUser: pmdkuser + + tasks: + + - name: "Update kernel packages" + package: + name: "kernel.x86_64" + state: latest + register: isUpdated + + - name: "Update OS packages" + package: + name: "*" + state: latest + + - name: "Reboot platform to apply updates" + reboot: + when: isUpdated.changed + + - name: "Add permanent pkg config variable to the system" + env: + state: present + name: PKG_CONFIG_PATH + value: /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig + + - name: "Rocky - adding additional repositories" + block: + - name: "Rocky - adding epel repository" + shell: yum install epel-release -y + + - name: "Rocky - enabling Power Tools" + shell: dnf config-manager --enable crb + + - name: "Install VALGRIND deps" + package: + state: present + name: + - autoconf + - automake + - file + - findutils + - git + + - name: "Install PMDK base deps" + package: + state: present + name: + - cmake + - git + - daxctl-devel + - make + - ndctl-devel + - passwd + - pkgconfig + + - name: "Install benchmarks deps (optional)" + package: + state: present + name: + - glib2-devel + + - name: "Install examples deps (optional)" + package: + state: present + name: + - fuse + - fuse-devel + - ncurses-devel + - libuv-devel + + - name: "Install documentation deps (optional)" + package: + state: present + name: + - pandoc + + - name: "Install tests deps" + package: + state: present + name: + - bc + - gdb + - libunwind-devel + - ndctl + - openssh-server + - strace + + - name: "Install packaging deps" + package: + state: present + name: + - rpm-build + - rpm-build-libs + - rpmdevtools + + - name: "Install miscellaneous deps" + package: + state: present + name: + - clang + - lbzip2 + - man + - python3 + - python3-flake8 + - rsync + - shadow-utils + - sudo + - tar + - which + - xmlto + + - name: "Run the install-valgrind script with arguments" + script: ../docker/images/install-valgrind.sh rockylinux + + - name: "Add new user" + shell: | + #!/usr/bin/env bash + export USER={{ testUser }} + export USERPASS=pmdkpass + useradd -m $USER + echo $USERPASS | passwd $USER --stdin + gpasswd wheel -a $USER + echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + - name: "Set variable OS" + env: + state: present + name: 'OS' + value: 'rockylinux/rockylinux' + + - name: "Set variable OS_VER" + env: + state: present + name: 'OS_VER' + value: '9' + + - name: "Set variable PACKAGE_MANAGER" + env: + state: present + name: 'PACKAGE_MANAGER' + value: 'rpm' + + - name: "Set variable NOTTY" + env: + state: present + name: 'NOTTY' + value: '1' From 202344ffe051ecca3dc7ca6154d9551e38037007 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 11 May 2023 19:07:40 +0200 Subject: [PATCH 2/2] common: increase Ansible playbookss usability - extend rockylinux to support version 8 - disable new user creation by default - provide new user password from command line - add ipmctl installation - conditional namespace destroy There is no namespace when running script for the first time. Ignore errors of namespace destroy to avoid ansible error. - add jq and libndctl-devel as it is required by pmem istallation procedure - cal install-valgrind.sh w/o OS name - disable selinuxand apparmor Disable selinuxand apparmor as it blocks proper self-runner service start. - self-hosted runner setup procedure documented - add link to ansible documentation - divide PMem setup procedure into several steps - rockylinux palybook documentation update - configure-pmem.yml documentation update - opensuse palybook documentation update Signed-off-by: Gromadzki, Tomasz --- utils/ansible/README.md | 208 ++++++++--- utils/ansible/configure-pmem.yml | 40 ++- utils/ansible/library/env.py | 337 ------------------ utils/ansible/opensuse-setup.yml | 53 ++- ...ylinux9-setup.yml => rockylinux-setup.yml} | 69 +++- 5 files changed, 280 insertions(+), 427 deletions(-) delete mode 100644 utils/ansible/library/env.py rename utils/ansible/{rockylinux9-setup.yml => rockylinux-setup.yml} (59%) diff --git a/utils/ansible/README.md b/utils/ansible/README.md index d6d42a32391..50c59df34e0 100644 --- a/utils/ansible/README.md +++ b/utils/ansible/README.md @@ -1,64 +1,176 @@ -Persistent Memory Development Kit +# Persistent Memory Development Kit -This is utils/ansible/README. +This is utils/ansible/README.md. -The scripts in this directory allow you to set up an RockyLinux and OpenSuSe +The scripts in this directory allow you to set up a RockyLinux and OpenSUSE +environment on a real hardware and build a PMDK project on it. -environment on a real HW and build a PMDK project in it. +# Installing Ansible +To use playbooks it is required to install Ansible first. It must be done +on a computer that will be used to execute the script, not necessarily +on the target platform. -To use playbooks it is required to install Ansible first. It must be done on computer that will be - used to execute script, not on target platform. - -Commands: +Please check ansible documentation on available installation methods. +https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html +Alternatively, install it from ready to use packages as shown below: +```sh +sudo dnf install ansible-core +# or +sudo zypper install ansible +# or +sudo apt install ansible-core ``` -ansible-playbook -i , opensuse-setup.yml --extra-vars - "host=all ansible_user=root ansible_password= testUser=pmdkuser" - ``` - +# Provisioning basics +## Provisioning the target platform +Use the command below to setup the PMDK software development environment: +```sh +export TARGET_IP= # ip of the target +export ROOT_PASSWORD= # a password of root on the target +export SETUP_SCRIPT= # opensuse-setup.yml or rockylinux-setup.yml + +ansible-playbook -i $TARGET_IP, $SETUP_SCRIPT \ + --extra-vars "host=all ansible_user=root ansible_password=$ROOT_PASSWORD \ + testUser=pmdkuser testUserPass=pmdkpass" ``` -ansible-playbook -i , rockylinux-setup.yml --extra-vars - "host=all ansible_user=root ansible_password= testUser=pmdkuser" - ``` - -Those commands above will install the required packages to build PMDK tests. - +**Note**: If the Linux kernel is outdated, `opensuse-setup.yml` and +`rockylinux-setup.yml` playbooks will reboot the target platform. + +## Provisioning persistent memory +Use the below command to configure persistent memory on Intel servers to be +used for PMDK libraries tests execution. +```sh +export TARGET_IP= # ip of the target +export ROOT_PASSWORD= # a password of root on the target +ansible-playbook -i $TARGET_IP, configure-pmem.yml \ + --extra-vars "host=all ansible_user=root ansible_password=$ROOT_PASSWORD \ + newRegions=true testUser=pmdkuser" ``` -ansible-playbook -i , configure-pmem.yml --extra-vars - "host=all ansible_user=root ansible_password= testUser=pmdkuser" - ``` - -This command will configure regions and namespaces on DIMMs. - -NOTE: - -- If platform does not have DIMM's regions configured earlier you can add additional var for - configureProvisioning.yml playbook: newRegions=true eg. - +The script creates a new region and set of namespaces regardless of the +configuration already available on the target platform. + +**Note**: Every time when new region is created (`newRegions=true`) the playbook +will reboot the target platform. + +**Note**: The given above command can be used whenever full reinitialization +of persistent memory is required. + +**Note**: Configured regions are required to create namespaces on the DIMMs. + +### Namespace re-initialization +The following command will delete all existing namespaces and create new ones. +It can be used to perform a full memory cleanup as part of a reinitialization of +the test environment. + +**Note**: It is NOT required to re-create regions with the `newRegions=true` +parameter in this case. +```sh +export TARGET_IP= # ip of the target +export ROOT_PASSWORD= # a password of root on the target +ansible-playbook -i $TARGET_IP, configure-pmem.yml \ + --extra-vars "host=all ansible_user=root ansible_password=$ROOT_PASSWORD \ + testUser=pmdkuser" ``` -ansible-playbook -i , configureProvisioning.yml --extra-vars - "host=all ansible_user=root ansible_password= newRegions=true testUser=pmdkuser" - ``` - -This will reboot the platform. - -Configured regions are required to create namespaces on the DIMMs. - -- If Linux kernel is outdated, opensuseAnsible and rockyAnsible playbooks will reboot target platform. - -- It is possible to run playbooks inside target platform but if notes above occurs then you need to rerun this playbook. - -To run playbooks inside the platform please comment line: - -` - hosts: "{{ host }}"` - -and uncomment +# Provisioning from the target platform itself +It is possible to run playbooks directly on the target platform. +To run playbooks inside the platform please comment out the line: +``` +- hosts: "{{ host }}" +``` +uncomment the following two: ``` # - hosts: localhost # connection: local ``` +and run commands as follows e.g. +```sh +export SETUP_SCRIPT= # opensuse-setup.yml or rockylinux-setup.yml +sudo ansible-playbook $SETUP_SCRIPT --extra-vars "testUser=pmdkuser" +``` +**Note**: If a reboot is necessary, as described above, perform it manually and +rerun the playbook withot in question. + +And next: +```sh +sudo ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser newRegions=true" +# you will have to perform a reboot manually +reboot +# and re-run the playbook without newRegions=true to finalize the setup +sudo ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser" +``` -and run with example command +# Example - GitHub self-hosted runner setup +The sequence of commands below presents an example procedure for how to setup +a new server, with the base OS already installed, to be used as a self-hosted +GHA runner without a control node. + +## Provisioning the platform and persistent memory +### For RockyLinux +```sh +# as root: +dnf install git-core -y +dnf install ansible-core -y +git clone https://github.com/pmem/pmdk.git +cd pmdk/utils/ansible +``` +Update playbooks to be used directly on the target as described [above](#provisioning-from-the-target-platform-itself) +and execute: +``` +# as root: +ansible-playbook ./rockylinux-setup.yml --extra-vars "testUser=pmdkuser testUserPass=pmdkpass" +# reboot shall be performed only if the playbook requests to do it. +reboot +# ... +cd pmdk/utils/ansible +ansible-playbook ./rockylinux-setup.yml --extra-vars "testUser=pmdkuser testUserPass=pmdkpass" +ansible-playbook ./configure-pmem.yml --extra-vars "newRegions=true" +reboot +# ... +cd pmdk/utils/ansible +# note - no newRegions=true when running the playbook after the reboot +ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser" +cd +rm -rf pmdk +``` + +### For OpenSUSE +```sh +# as root: +zypper install git-core -y +zypper install ansible -y +git clone https://github.com/pmem/pmdk.git +cd pmdk/utils/ansible +``` +Update playbooks to be used directly on the target as described [above](#provisioning-from-the-target-platform-itself) +and execute: +``` +# as root: +ansible-playbook ./opensuse-setup.yml --extra-vars "testUser=pmdkuser testUserPass=pmdkpass" +# reboot shall be performed only if the playbook requests to do it. +reboot +# ... +cd pmdk/utils/ansible +ansible-playbook ./opensuse-setup.yml --extra-vars "testUser=pmdkuser testUserPass=pmdkpass" +ansible-playbook ./configure-pmem.yml --extra-vars "newRegions=true" +reboot +# ... +cd pmdk/utils/ansible +# note - no newRegions=true when running the playbook after the reboot +ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser" +cd +rm -rf pmdk +``` -`sudo ansible-playbook opensuse-setup.yml --extra-vars "testUser=pmdkuser"` +## Installing and setting up a GitHub Actions runner +Installation and configuration of a self-hosted runner (as pmdkuser): +```sh +mkdir actions-runner && cd actions-runner +curl -o actions-runner-linux-x64-2.304.0.tar.gz -L \ +https://github.com/actions/runner/releases/download/v2.304.0/actions-runner-linux-x64-2.304.0.tar.gz +tar xzf ./actions-runner-linux-x64-2.304.0.tar.gz +./config.cmd --url https://github.com/pmem/pmdk --token T_O_K_E_N__F_R_O_M__G_I_T_H_U_B +tmux +./run.cmd +``` +Close session leaving the tmux session in the background (`CTRL+b d`). diff --git a/utils/ansible/configure-pmem.yml b/utils/ansible/configure-pmem.yml index 418579c348a..36209ec77b3 100644 --- a/utils/ansible/configure-pmem.yml +++ b/utils/ansible/configure-pmem.yml @@ -1,14 +1,27 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2023, Intel Corporation -# This playbook is designed to configure regions and namespaces on DIMMs so user can execute -# tests later. Playbook usage is described in README.md file. -# Steps below are divided into 3 parts: removing previous namespaces (if existed), creating new regions -# (if requested by the user) and creating namespaces on that regions. +# This playbook is designed to configure regions and namespaces on DIMMs +# so users can execute tests later. Playbook usage is described in +# the README.md file. +# The steps below are divided into 3 parts: removing previous namespaces +# (if existed), creating new regions (if requested by the user) +# and creating namespaces on that regions. +# +# Shell script implemented in this playbook for namespace creation +# will create 9 DAX namespaces with aligned sizes to fit the first region +# and 1 FSDAX namespace to fit the second region. +# It is assumed that system contains 2 interleaved regions beforehand. +# Setting "newRegions" to "true" will do that. +# +# Below are examples of how to use this file: +# +# 1) setup PMem for the first time (establish regions): +# sudo ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser newRegions='true'" +# +# 2) setup PMem if it already has been initialized before: +# sudo ansible-playbook ./configure-pmem.yml --extra-vars "testUser=pmdkuser" # -# Shell script implemented in this playbook for namespace creation will create 9 DAX namespaces with aligned sizes -# to fit first region and 1 FSDAX namespace to fit second region. It is assumed that system contains 2 interleaved regions -# beforehand. Setting "newRegions" to "true" will do that. - hosts: "{{ host }}" # - hosts: localhost @@ -24,10 +37,12 @@ - name: "Unmount namespaces if they exist" shell: sudo umount /dev/pmem* || true + - name: "Disable current namespaces" + shell: sudo ndctl disable-namespace all || true + register: namespaces + - name: "Destroy current namespaces" - shell: | - sudo ndctl disable-namespace all - sudo ndctl destroy-namespace all + shell: sudo ndctl destroy-namespace all || true register: namespaces - debug: var=namespaces @@ -106,7 +121,12 @@ if [ ! -d "${MOUNT_POINT}" ]; then sudo mkdir ${MOUNT_POINT} fi + register: script + + - debug: var=script + - name: "Create new namespace configuration" + shell: | sudo mkfs.ext4 -F /dev/${pmem_name} sudo mount -o dax /dev/${pmem_name} ${MOUNT_POINT} sudo chown -R {{ testUser }} ${MOUNT_POINT} diff --git a/utils/ansible/library/env.py b/utils/ansible/library/env.py deleted file mode 100644 index 05dd3302207..00000000000 --- a/utils/ansible/library/env.py +++ /dev/null @@ -1,337 +0,0 @@ -#!/usr/bin/python - -# -# SPDX-License-Identifier: BSD-3-Clause -# Copyright 2019-2023, Intel Corporation -# - -import os -from ansible.module_utils.basic import AnsibleModule - -DOCUMENTATION = ''' ---- -module: env - -short_description: Module for managing environmental variables on remote hosts - -description: - - "Module for set and unset environmental variables on remote hosts. - Setting is done by writing export definitions to the file* (this should help with keeping persistence of values - between reboots) and then execute 'source' command (in order to feed current session with exported variables). - - - ---- - - * file: the file under the care of this module, specified by 'path' parameter. By default it is a file in - /etc/profile.d/" - -options: - name: - description: - - This is the name of the variable to manage - required: true - value: - description: - - This is the value of the variable to manage. If 'state'='present', this option is required. - required: false - state: - description: - - If 'present', ensure that given variable is set to given value. This is the default. - required: false - default: present - choices: [ present ] - path: - description: - - This is the path of a file where export definitions will be written. Usually you don't want to change it. - required: false - default: /etc/profile.d/ansible_env_module_definitions.sh - -author: - - dpysx -''' - -EXAMPLES = ''' -# Set http_proxy: -- name: set http proxy - env: - name: http_proxy - value: http://example.com:80 -''' - -RETURN = ''' -old_value: - description: Value of variable, before the module was called. - type: str -''' - - -# ####################################################################################### -# ########################## General helpers ########################################## -# ####################################################################################### - - -def check_prerequisites(module, result): - """Check if passed module and result are valid types from AnsibleModule.""" - if not isinstance(module, AnsibleModule): - raise TypeError("Given module is not valid!") - - if not isinstance(result, dict): - raise TypeError("Given result is not valid!") - - -# ####################################################################################### -# ################### Helpers for dealing with system commands ######################## -# ####################################################################################### - - -def escape_quotes(string): - """Escape every double quote char with a backslash.""" - return string.replace('"', '\\"') - - -def run_command(module, result, command): - """Execute command and return its stdout; when status not zero, fail module execution.""" - check_prerequisites(module, result) - - command = 'bash -lc "' + escape_quotes(command) + '"' - - rc, stdout, stderr = module.run_command(command) - - if rc != 0: - fail_message = "Command '" + command + "' failed with status code " + str( - rc) + ", stdout: '" + stdout + "', stderr: '" + stderr + "'." - module.fail_json(msg=fail_message, **result) - - return stdout - - -# ####################################################################################### -# ###################### Helpers for handling checking env vars ####################### -# ####################################################################################### - - -def get_env_value_or_empty(module, result, name): - """Obtain value of variable and return it; if not present, return empty string.""" - check_prerequisites(module, result) - - print_variable = 'echo "$' + name + '"' - variable_value = run_command(module, result, print_variable) - - return variable_value.replace('\n', '') - - -def is_env_present(module, result, name): - """Check if variable with given name is present in system.""" - check_prerequisites(module, result) - - env_value = get_env_value_or_empty(module, result, name) - if env_value == "": - return False - else: - return True - - -# ####################################################################################### -# ########################## Helpers for file handling ################################ -# ####################################################################################### - - -valid_shebang = "#!/usr/bin/env bash\n" - - -def read_file_lines(module, result, filename): - """Read file and return its lines in a form of list.""" - content = [] - try: - file = open(filename, "r") - content = file.readlines() - file.close() - except IOError: - fail_message = "Cannot open file '" + filename + "' for reading." - module.fail_json(msg=fail_message, **result) - - return content - - -def is_valid_shebang(module, result, filename): - """Check if file has valid, bash shebang line.""" - check_prerequisites(module, result) - - file_lines = read_file_lines(module, result, filename) - - global valid_shebang - if len(file_lines) == 0 or file_lines[0] != valid_shebang: - return False - else: - return True - - -def write_file_lines(module, result, filename, lines): - """Write all lines to the file.""" - check_prerequisites(module, result) - - changed = False - if not os.access(filename, os.F_OK): - changed = True - - try: - file = open(filename, 'w') - except IOError: - fail_message = "Cannot open file '" + filename + "' for write." - module.fail_json(msg=fail_message, **result) - - try: - content = [] - for line in lines: - if not line.endswith('\n'): - s = line + "\n" - else: - s = line - content.append(s) - - file.writelines(content) - changed = True - except: - fail_message = "Cannot write to file '" + filename + "'." - module.fail_json(msg=fail_message, **result) - finally: - file.close() - - result['changed'] = changed - - -def write_variable_to_file(module, result, name, value, filename): - """Write export definition of the variable to the file. Removes possible duplicates.""" - check_prerequisites(module, result) - global valid_shebang - - content = [] - env_entry_start = "export " + name + "=" - env_entry = env_entry_start + '"' + escape_quotes(value) + '"\n' - - if os.access(filename, os.F_OK): - content = read_file_lines(module, result, filename) - - if not is_valid_shebang(module, result, filename): - content.insert(0, valid_shebang) - - # remove all entries for current variable: - filtered_content = [] - for line in content: - if not line.startswith(env_entry_start): - filtered_content.append(line) - - content = filtered_content - content.append(env_entry) - - write_file_lines(module, result, filename, content) - result['changed'] = True - - else: - content.append(valid_shebang) - content.append(env_entry) - write_file_lines(module, result, filename, content) - try: - os.chmod(filename, 0o755) - result['changed'] = True - except: - fail_message = "Cannot change file '" + filename + "' permissions to 755." - module.fail_json(msg=fail_message, **result) - - -# ####################################################################################### -# ############### Helpers for exporting / unset vars to current session ############### -# ####################################################################################### - - -def import_variables_from_file(module, result, filename): - """Execute 'source' command with file parameter in order to import definitions to the current session.""" - check_prerequisites(module, result) - - result['changed'] = True - - load_variables_from_file = 'source "' + filename + '"' - run_command(module, result, load_variables_from_file) - - -def export_variable(module, result, name, value): - """Execute 'export' command in order to add exported definition.""" - check_prerequisites(module, result) - - result['changed'] = True - export_var = "export " + name + '="' + escape_quotes(value) + '"' - run_command(module, result, export_var) - - -# ####################################################################################### -# ########################## Main module functions #################################### -# ####################################################################################### - - -def present_flow(module, result, name, value, filename): - """Execute module flow for 'present' module mode.""" - check_prerequisites(module, result) - - current_value = get_env_value_or_empty(module, result, name) - result['old_value'] = current_value - - if value is not None: - - if is_env_present(module, result, name) and current_value == value: - module.exit_json(**result) - - result['changed'] = True - - if not module.check_mode: - write_variable_to_file(module, result, name, value, filename) - import_variables_from_file(module, result, filename) - export_variable(module, result, name, value) - - module.exit_json(**result) - - else: - if is_env_present(module, result, name): - module.exit_json(**result) - else: - module.fail_json("variable is not set!", **result) - - -def run_module(): - """Prepare parameter and return value object, select and execute proper module flow.""" - - module_args = dict( - state=dict(type='str', default='present', choices=['present']), - path=dict(type='str', default='/etc/profile.d/ansible_env_module_definitions.sh'), - name=dict(type='str', required=True), - value=dict(type='str'), - ) - - result = dict( - changed=False, - old_value='' - ) - - module = AnsibleModule( - argument_spec=module_args, - supports_check_mode=True - ) - - # state = module.params['state'] - name = module.params['name'] - value = module.params['value'] - path = module.params['path'] - - # arguments' reasonableness check - if value is None: - module.fail_json(msg="There should be 'value' set as well!", **result) - - present_flow(module, result, name, value, path) - - # flow functions should end module's execution; when otherwise, there is some ancient evil in here: - module.fail_json(msg="Unexpected execution path, this is a bug in this module!", **result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/utils/ansible/opensuse-setup.yml b/utils/ansible/opensuse-setup.yml index 5a431b97221..92a614b19df 100644 --- a/utils/ansible/opensuse-setup.yml +++ b/utils/ansible/opensuse-setup.yml @@ -1,14 +1,16 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2023, Intel Corporation -# This playbook is designed to install all required packages and configure openSUSE to execute tests. -# Playbook description and how to use it is available in README.md file +# This playbook is designed to install all required packages and configure +# OpenSUSE to execute tests. +# The playbook description and how to use it are available in the README.md file. - hosts: "{{ host }}" # - hosts: localhost # connection: local vars: - testUser: pmdkuser + testUser: null + testUserPass: pmdkpass tasks: @@ -45,7 +47,7 @@ repo: 'http://download.opensuse.org/distribution/leap/15.4/repo/oss' state: present - - name: "Install VALGRIND deps" + - name: "Install Valgrind dependencies" package: state: present name: @@ -55,7 +57,7 @@ - findutils - git - - name: "Install PMDK base deps" + - name: "Install PMDK base dependencies" package: state: present name: @@ -66,14 +68,15 @@ - make - pkgconfig - systemd + - libndctl-devel - - name: "Install benchmarks deps (optional)" + - name: "Install benchmarks dependencies (optional)" package: state: present name: - glib2-devel - - name: "Install examples deps (optional)" + - name: "Install examples dependencies (optional)" package: state: present name: @@ -82,13 +85,13 @@ - ncurses-devel - libuv-devel - - name: "Install documentation deps (optional)" + - name: "Install documentation dependencies (optional)" package: state: present name: - pandoc - - name: "Install tests deps" + - name: "Install tests dependencies" package: state: present name: @@ -97,14 +100,14 @@ - libunwind-devel - strace - - name: "Install packaging deps" + - name: "Install packaging dependencies" package: state: present name: - rpm-build - rpmdevtools - - name: "Install miscellaneous deps" + - name: "Install miscellaneous dependencies" package: state: present name: @@ -118,8 +121,9 @@ - tar - which - xmlto + - jq - - name: "Install NDCTL deps" + - name: "Install ndctl dependencies" package: state: present name: @@ -132,17 +136,35 @@ - libuuid-devel - systemd-devel - - name: "Run the install-valgrind script with arguments" - script: ../docker/images/install-valgrind.sh fedora + - name: "Install ipmctl" + package: + state: present + name: + - ipmctl + + - name: "Install valgrind from source" + script: ../docker/images/install-valgrind.sh - name: "Run the install-libndctl script with arguments" script: ../docker/images/install-libndctl.sh tags/v70.1 + # Disable AppArmor. + # AppArmor may block proper GHA runner installation and startup. + # ==`Suse` condition is inherited from the original version of + # the ansible playbook that has been created for many OSes. + - name: Disable AppArmor + service: + name: apparmor + state: stopped + enabled: no + ignore_errors: yes + when: ansible_facts['os_family'] == 'Suse' + - name: "Add new user" shell: | #!/usr/bin/env bash export USER={{ testUser }} - export USERPASS=pmdkpass + export USERPASS={{ testUserPass }} useradd -m $USER export PFILE=./password echo $USERPASS > $PFILE @@ -152,6 +174,7 @@ sed -i 's/# %wheel/%wheel/g' /etc/sudoers groupadd wheel gpasswd wheel -a $USER + when: testUser != None - name: "Set variable OS" env: diff --git a/utils/ansible/rockylinux9-setup.yml b/utils/ansible/rockylinux-setup.yml similarity index 59% rename from utils/ansible/rockylinux9-setup.yml rename to utils/ansible/rockylinux-setup.yml index b032664cc0d..0e2d4959c62 100644 --- a/utils/ansible/rockylinux9-setup.yml +++ b/utils/ansible/rockylinux-setup.yml @@ -1,17 +1,19 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2023, Intel Corporation -# This playbook is designed to install all required packages and configure Rocky Linux 9 to execute tests. -# Playbook description and how to use it is available in README.md file +# This playbook is designed to install all required packages and +# configure Rocky Linux to execute tests. +# The playbook description and how to use it are available +# in the README.md file. - hosts: "{{ host }}" # - hosts: localhost # connection: local vars: - testUser: pmdkuser + testUser: null + testUserPass: pmdkpass tasks: - - name: "Update kernel packages" package: name: "kernel.x86_64" @@ -33,15 +35,22 @@ name: PKG_CONFIG_PATH value: /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig +# For `ansible_distribution_*` variables see: +# https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html#commonly-used-facts - name: "Rocky - adding additional repositories" block: - name: "Rocky - adding epel repository" shell: yum install epel-release -y - - name: "Rocky - enabling Power Tools" + - name: "Rocky 9 - enabling Power Tools" shell: dnf config-manager --enable crb + when: ansible_distribution_major_version == "9" + + - name: "Rocky 8 - enabling Power Tools" + shell: dnf config-manager --enable powertools + when: ansible_distribution_major_version == "8" - - name: "Install VALGRIND deps" + - name: "Install Valgrind dependencies" package: state: present name: @@ -51,7 +60,7 @@ - findutils - git - - name: "Install PMDK base deps" + - name: "Install PMDK base dependencies" package: state: present name: @@ -63,13 +72,13 @@ - passwd - pkgconfig - - name: "Install benchmarks deps (optional)" + - name: "Install benchmarks dependencies (optional)" package: state: present name: - glib2-devel - - name: "Install examples deps (optional)" + - name: "Install examples dependencies (optional)" package: state: present name: @@ -78,13 +87,13 @@ - ncurses-devel - libuv-devel - - name: "Install documentation deps (optional)" + - name: "Install documentation dependencies (optional)" package: state: present name: - pandoc - - name: "Install tests deps" + - name: "Install tests dependencies" package: state: present name: @@ -95,7 +104,7 @@ - openssh-server - strace - - name: "Install packaging deps" + - name: "Install packaging dependencies" package: state: present name: @@ -103,7 +112,7 @@ - rpm-build-libs - rpmdevtools - - name: "Install miscellaneous deps" + - name: "Install miscellaneous dependencies" package: state: present name: @@ -118,19 +127,37 @@ - tar - which - xmlto + - jq + + - name: "Install ipmctl" + package: + state: present + name: + - ipmctl - - name: "Run the install-valgrind script with arguments" - script: ../docker/images/install-valgrind.sh rockylinux + - name: "Install valgrind from source" + script: ../docker/images/install-valgrind.sh + + # Disable SELinux. + # SELinux may block proper GHA runner installation and startup. + # !=`Debian` condition is inherited from the original version of + # the ansible playbook that has been created for many OSes. + - name: Disable selinux - distribution other than Debian based + selinux: + state: disabled + ignore_errors: yes + when: ansible_facts['os_family'] != 'Debian' - name: "Add new user" shell: | #!/usr/bin/env bash export USER={{ testUser }} - export USERPASS=pmdkpass + export USERPASS={{ testUserPass }} useradd -m $USER echo $USERPASS | passwd $USER --stdin gpasswd wheel -a $USER echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + when: testUser != none - name: "Set variable OS" env: @@ -138,11 +165,19 @@ name: 'OS' value: 'rockylinux/rockylinux' - - name: "Set variable OS_VER" + - name: "Set variable OS_VER (9)" env: state: present name: 'OS_VER' value: '9' + when: ansible_distribution_major_version == "9" + + - name: "Set variable OS_VER (8)" + env: + state: present + name: 'OS_VER' + value: '8' + when: ansible_distribution_major_version == "8" - name: "Set variable PACKAGE_MANAGER" env: