├── .ansible-lint ├── .github └── workflows │ └── lint.yaml ├── .gitignore ├── .yamllint.yml ├── LICENSE ├── README.md ├── defaults └── main.yml ├── meta └── main.yml └── tasks └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | skip_list: 2 | - 'yaml' 3 | - 'package-latest' 4 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint 3 | # yamllint disable-line rule:truthy 4 | on: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | lint: 14 | name: Linting 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Install dependencies 21 | run: pip3 install yamllint 22 | 23 | - name: Run Yaml Lint 24 | run: | 25 | yamllint . 26 | 27 | - name: Run Ansible Lint 28 | uses: ansible/ansible-lint@main 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: 6 | max: 230 7 | level: warning 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 VoidQuark 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible role - EL Patching 2 | 3 | [![License](https://img.shields.io/github/license/voidquark/el_patching)](LICENSE) 4 | 5 | Apply OS patches on Enterprise Linux (RHEL) and other Red Hat derivatives (e.g. CentOS, Rocky, Alma, Fedora). You can decide which patching method you want to use. There are 3 methods: 6 | 7 | - `all` - Apply all patches on target a host 8 | - `security` - Apply only security patches on target a host 9 | - `bugfix` - Apply only bugfix patches on target a host 10 | 11 | **I recommend visiting the [blog post](https://voidquark.com/blog/ansible-linux-os-patching/) for detailed information, usage example, and my recommendation.** 12 | 13 | ## Requirements 14 | 15 | Only dnf must be available on the target machine. 16 | 17 | ## Role Variables 18 | 19 | - **Default Variables**. Usually, there is no need to change this but rather overwrite the value in `host_vars` or `group_vars` if required. 20 | 21 | | Variable Name | Default Value | Description 22 | | ----------- | ----------- | ----------- | 23 | | `el_patching_required_packages` | `"yum-utils"` | It is required to install yum-utils as this role verifies reboot with `needs-restarting`. 24 | | `el_patching_auto_reboot` | `false` | By default do not reboot the target host. Only verify if a reboot is required. 25 | | `el_patching_reboot_timeout` | `600` | By default auto reboot is disabled but the default timeout value is set to 5 minutes. Value is in `seconds`. 26 | | `el_patching_method` | `"security"` | By default apply only `security` patches on the target host. Possible values `"security"/"bugfix"/"all"` 27 | 28 | - **group_vars** or **host_vars** variables. 29 | 30 | | Variable Name | Example Usage | Required | Description 31 | | ----------- | ----------- | ----------- | ----------- | 32 | | `el_patching_exclude_packages` |
el_patching_exclude_packages:
 - tar
 - zip
| No | Exclude packages during patching. 33 | | `el_patching_update_cache` | `true` | No | Force dnf to check if cache is out of date and re-download if needed. 34 | 35 | ## Dependencies 36 | 37 | No Dependencies 38 | 39 | ## Example Playbook 40 | 41 | Create the following playbook. 42 | ```yaml 43 | - name: Apply OS Patches 44 | hosts: your_patching_inventory_group_or_host 45 | become: true 46 | roles: 47 | - voidquark.el_patching 48 | ``` 49 | 50 | ## Example execution 51 | 52 | - Normal Execution 53 | ```shell 54 | ansible-playbook -i inventory/hosts playbook.yml 55 | ``` 56 | 57 | - If you want to run playbook in check mode 58 | ```shell 59 | ansible-playbook -i inventory/hosts playbook.yml --check 60 | ``` 61 | 62 | 63 | ## License 64 | 65 | MIT 66 | 67 | ## Author Information 68 | 69 | Created by [VoidQuark](https://voidquark.com) 70 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for el_patching 3 | el_patching_required_packages: "yum-utils" 4 | el_patching_reboot_timeout: 600 5 | el_patching_method: "security" 6 | el_patching_auto_reboot: false 7 | 8 | # Optional exclude variable for group_vars or host_vars 9 | # el_patching_exclude_packages: 10 | # - tar 11 | # - zip 12 | # el_patching_update_cache: true 13 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: voidquark 4 | description: Apply Linux OS patches 5 | company: VoidQuark 6 | 7 | license: MIT 8 | 9 | min_ansible_version: "2.1" 10 | 11 | platforms: 12 | - name: Fedora 13 | versions: 14 | - all 15 | - name: EL 16 | versions: 17 | - "8" 18 | - "9" 19 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for el_patching 3 | 4 | - name: Ensure that need-restarting binary is present 5 | ansible.builtin.dnf: 6 | name: "{{ el_patching_required_packages }}" 7 | state: present 8 | 9 | - name: Update all packages 10 | ansible.builtin.dnf: 11 | name: "*" 12 | state: latest 13 | update_cache: "{{ el_patching_update_cache | default(omit) }}" 14 | exclude: "{{ el_patching_exclude_packages | default(omit) }}" 15 | when: el_patching_method == "all" 16 | 17 | - name: Apply security patches only 18 | ansible.builtin.dnf: 19 | name: "*" 20 | security: true 21 | state: latest 22 | update_cache: "{{ el_patching_update_cache | default(omit) }}" 23 | exclude: "{{ el_patching_exclude_packages | default(omit) }}" 24 | when: el_patching_method == "security" 25 | 26 | - name: Apply bugfix patches only 27 | ansible.builtin.dnf: 28 | name: "*" 29 | bugfix: true 30 | state: latest 31 | update_cache: "{{ el_patching_update_cache | default(omit) }}" 32 | exclude: "{{ el_patching_exclude_packages | default(omit) }}" 33 | when: el_patching_method == "bugfix" 34 | 35 | - name: Verify if restart is required 36 | ansible.builtin.command: 37 | cmd: needs-restarting --reboothint 38 | register: __el_patching_need_restart 39 | failed_when: __el_patching_need_restart.rc > 1 40 | changed_when: false 41 | 42 | - name: Inform user if reboot is required 43 | ansible.builtin.debug: 44 | msg: "Reboot is required to apply patches." 45 | when: __el_patching_need_restart.rc == 1 46 | 47 | - name: Reboot host 48 | ansible.builtin.reboot: 49 | reboot_timeout: "{{ el_patching_reboot_timeout }}" 50 | when: el_patching_auto_reboot | bool and __el_patching_need_restart.rc == 1 51 | --------------------------------------------------------------------------------