diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..d5bbee2 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,18 @@ +--- +profile: production + +exclude_paths: + - .cache/ + - .github/ + - molecule/ + +offline: false + +supported_ansible_also: + - ">=2.12" + +verbosity: 1 + +warn_list: + - experimental + - yaml[truthy] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9db52ea --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,101 @@ +name: Molecule CI + +on: + pull_request: + branches: + - "master" + - "main" + push: + branches: + - "master" + - "main" + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + - name: Run lint + run: make lint + + test: + name: Test ${{ matrix.os }}-${{ matrix.version }} (upgrade=${{ matrix.upgrade }}, style=${{ matrix.style }}, freq=${{ matrix.frequency }}) + runs-on: ubuntu-latest + needs: lint + strategy: + fail-fast: false + matrix: + os: [debian, ubuntu] + version: ['12', '2204', '2404'] + upgrade: ['false', 'true'] + style: ['safe', 'full', 'dist'] + frequency: ['once', 'boot', 'always'] + + # Exclude invalid OS/version combinations + exclude: + # Debian only has version 12 + - os: debian + version: '2204' + - os: debian + version: '2404' + # Ubuntu doesn't have version 12 + - os: ubuntu + version: '12' + + # When upgrade is false, only test one combination of style/frequency + # (since they don't apply when upgrade is disabled) + - upgrade: 'false' + style: 'full' + - upgrade: 'false' + style: 'dist' + - upgrade: 'false' + frequency: 'boot' + - upgrade: 'false' + frequency: 'always' + + # Add the image mapping based on OS and version + include: + - os: debian + version: '12' + image: geerlingguy/docker-debian12-ansible:latest + - os: ubuntu + version: '2204' + image: geerlingguy/docker-ubuntu2204-ansible:latest + - os: ubuntu + version: '2404' + image: geerlingguy/docker-ubuntu2404-ansible:latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Run molecule test + run: molecule test + env: + MOLECULE_OS: ${{ matrix.os }} + MOLECULE_VERSION: ${{ matrix.version }} + MOLECULE_IMAGE: ${{ matrix.image }} + APT_UPGRADE: ${{ matrix.upgrade }} + APT_UPGRADE_STYLE: ${{ matrix.style }} + APT_UPGRADE_FREQUENCY: ${{ matrix.frequency }} diff --git a/.gitignore b/.gitignore index 097093d..04188a8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,11 @@ Icon ._* .Spotlight-V100 .Trashes -.vagrant -test -.history -.vscode +.ci-env +.ansible +__pycache__ +molecule*.log +.act/ +.#* +*.*# +.molecule-state/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3a73a2d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -language: python -python: "2.7" -env: - matrix: - - ANSIBLE_VERSION="2.3" - - ANSIBLE_VERSION="2.7.0" -before_install: - - sudo apt-get update -qq - - sudo apt-get install -qq python-apt python-pycurl -install: - - pip install ansible=="$ANSIBLE_VERSION" -script: - - echo localhost > inventory - - ansible-playbook -i inventory test.yml --syntax-check - - ansible-playbook -i inventory test.yml --connection=local --become - - > - ansible-playbook -i inventory test.yml --connection=local --become - | grep -q 'changed=0.*failed=0' - && (echo 'Idempotence test: pass' && exit 0) - || (echo 'Idempotence test: fail' && exit 1) -notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..30649a7 --- /dev/null +++ b/.yamllint @@ -0,0 +1,10 @@ +--- +extends: default +rules: + line-length: + max: 120 + level: warning + +# Ignore editor temporary/lock files (e.g. Emacs .#* files) that can appear in molecule dirs +ignore: | + **/.#* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6d76d9b --- /dev/null +++ b/Makefile @@ -0,0 +1,306 @@ +.PHONY: requirements lint test test-all test-debian12 test-ubuntu2204 test-ubuntu2404 \ + test-matrix test-matrix-debian test-matrix-ubuntu2204 test-matrix-ubuntu2404 + +# set default jobs to be quarter of cores +NCORES := $(shell getconf _NPROCESSORS_ONLN) +RAW_JOBS := $(shell echo $(NCORES) \* 0.75 | bc) +JOBS := $(shell echo "scale=0; ($(RAW_JOBS) + 0.5) / 1" | bc) +ifeq ($(JOBS),0) + JOBS := 1 +endif +override MAKEFLAGS += --jobs=$(JOBS) --output-sync=target + +requirements: + pip install -q -r requirements-dev.txt + +lint: + yamllint -c .yamllint defaults tasks vars meta + ansible-lint -c .ansible-lint defaults tasks vars meta + +# Default basic test with upgrade disabled +test: requirements lint test-matrix + +# OS-Specific Quick Tests (upgrade disabled) +test-debian12: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-quick \ + MOLECULE_SCENARIO_NAME=debian12-quick \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + molecule test + +test-ubuntu2204: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-quick \ + MOLECULE_SCENARIO_NAME=ubuntu2204-quick \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + molecule test + +test-ubuntu2404: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-quick \ + MOLECULE_SCENARIO_NAME=ubuntu2404-quick \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + molecule test + +# Quick parallel test across all OS (upgrade disabled) +test-all: test-debian12 test-ubuntu2204 test-ubuntu2404 + +# +# Comprehensive Test Matrix +# ------------------------- +# Tests all combinations of OS × upgrade settings +# Run with: make -j N test-matrix (where N is number of parallel jobs) +# + +# Full matrix targets (30 total scenarios) +test-matrix: test-matrix-debian test-matrix-ubuntu2204 test-matrix-ubuntu2404 + +test-matrix-debian: \ + test-debian12-upgrade-false \ + test-debian12-safe-once \ + test-debian12-safe-boot \ + test-debian12-safe-always \ + test-debian12-full-once \ + test-debian12-full-boot \ + test-debian12-full-always \ + test-debian12-dist-once \ + test-debian12-dist-boot \ + test-debian12-dist-always + +test-matrix-ubuntu2204: \ + test-ubuntu2204-upgrade-false \ + test-ubuntu2204-safe-once \ + test-ubuntu2204-safe-boot \ + test-ubuntu2204-safe-always \ + test-ubuntu2204-full-once \ + test-ubuntu2204-full-boot \ + test-ubuntu2204-full-always \ + test-ubuntu2204-dist-once \ + test-ubuntu2204-dist-boot \ + test-ubuntu2204-dist-always + +test-matrix-ubuntu2404: \ + test-ubuntu2404-upgrade-false \ + test-ubuntu2404-safe-once \ + test-ubuntu2404-safe-boot \ + test-ubuntu2404-safe-always \ + test-ubuntu2404-full-once \ + test-ubuntu2404-full-boot \ + test-ubuntu2404-full-always \ + test-ubuntu2404-dist-once \ + test-ubuntu2404-dist-boot \ + test-ubuntu2404-dist-always + +# +# Individual Test Scenario Definitions +# ------------------------------------- + +# Debian 12 scenarios +test-debian12-upgrade-false: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-upgrade-false \ + MOLECULE_SCENARIO_NAME=debian12-upgrade-false \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=false \ + molecule test + +test-debian12-safe-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-safe-once \ + MOLECULE_SCENARIO_NAME=debian12-safe-once \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-debian12-safe-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-safe-boot \ + MOLECULE_SCENARIO_NAME=debian12-safe-boot \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-debian12-safe-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-safe-always \ + MOLECULE_SCENARIO_NAME=debian12-safe-always \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-debian12-full-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-full-once \ + MOLECULE_SCENARIO_NAME=debian12-full-once \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-debian12-full-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-full-boot \ + MOLECULE_SCENARIO_NAME=debian12-full-boot \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-debian12-full-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-full-always \ + MOLECULE_SCENARIO_NAME=debian12-full-always \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-debian12-dist-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-dist-once \ + MOLECULE_SCENARIO_NAME=debian12-dist-once \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-debian12-dist-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-dist-boot \ + MOLECULE_SCENARIO_NAME=debian12-dist-boot \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-debian12-dist-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/debian12-dist-always \ + MOLECULE_SCENARIO_NAME=debian12-dist-always \ + MOLECULE_OS=debian MOLECULE_VERSION=12 MOLECULE_IMAGE=geerlingguy/docker-debian12-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=always \ + molecule test + +# Ubuntu 22.04 scenarios +test-ubuntu2204-upgrade-false: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-upgrade-false \ + MOLECULE_SCENARIO_NAME=ubuntu2204-upgrade-false \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=false \ + molecule test + +test-ubuntu2204-safe-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-safe-once \ + MOLECULE_SCENARIO_NAME=ubuntu2204-safe-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2204-safe-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-safe-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2204-safe-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2204-safe-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-safe-always \ + MOLECULE_SCENARIO_NAME=ubuntu2204-safe-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-ubuntu2204-full-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-full-once \ + MOLECULE_SCENARIO_NAME=ubuntu2204-full-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2204-full-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-full-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2204-full-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2204-full-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-full-always \ + MOLECULE_SCENARIO_NAME=ubuntu2204-full-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-ubuntu2204-dist-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-dist-once \ + MOLECULE_SCENARIO_NAME=ubuntu2204-dist-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2204-dist-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-dist-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2204-dist-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2204-dist-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2204-dist-always \ + MOLECULE_SCENARIO_NAME=ubuntu2204-dist-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2204 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2204-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=always \ + molecule test + +# Ubuntu 24.04 scenarios +test-ubuntu2404-upgrade-false: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-upgrade-false \ + MOLECULE_SCENARIO_NAME=ubuntu2404-upgrade-false \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=false \ + molecule test + +test-ubuntu2404-safe-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-safe-once \ + MOLECULE_SCENARIO_NAME=ubuntu2404-safe-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2404-safe-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-safe-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2404-safe-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2404-safe-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-safe-always \ + MOLECULE_SCENARIO_NAME=ubuntu2404-safe-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=safe APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-ubuntu2404-full-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-full-once \ + MOLECULE_SCENARIO_NAME=ubuntu2404-full-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2404-full-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-full-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2404-full-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2404-full-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-full-always \ + MOLECULE_SCENARIO_NAME=ubuntu2404-full-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=full APT_UPGRADE_FREQUENCY=always \ + molecule test + +test-ubuntu2404-dist-once: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-dist-once \ + MOLECULE_SCENARIO_NAME=ubuntu2404-dist-once \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=once \ + molecule test + +test-ubuntu2404-dist-boot: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-dist-boot \ + MOLECULE_SCENARIO_NAME=ubuntu2404-dist-boot \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=boot \ + molecule test + +test-ubuntu2404-dist-always: + MOLECULE_EPHEMERAL_DIRECTORY=.molecule-state/ubuntu2404-dist-always \ + MOLECULE_SCENARIO_NAME=ubuntu2404-dist-always \ + MOLECULE_OS=ubuntu MOLECULE_VERSION=2404 MOLECULE_IMAGE=geerlingguy/docker-ubuntu2404-ansible:latest \ + APT_UPGRADE=true APT_UPGRADE_STYLE=dist APT_UPGRADE_FREQUENCY=always \ + molecule test diff --git a/defaults/main.yml b/defaults/main.yml index 151078c..904d315 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,24 +1,15 @@ -# file: apt/defaults/main.yml - -apt_reset_source_list: no # reset the /etc/apt/sources.list to the default -apt_mirror_url: http://archive.ubuntu.com # the mirror from where to install packages -apt_cache_valid_time: 3600 # Time (in seconds) the apt cache stays valid -apt_install_recommends: no # whether or not to install the "recommended" packages -apt_install_suggests: no # whether or not to install the "suggested" packages -apt_autoremove: yes # remove packages that are no longer needed for dependencies -apt_clean: no # remove all cached .deb files -apt_autoremove_recommends: yes # whether to automatically remove "recommended" packages -apt_autoremove_suggests: yes # whether to automatically remove "suggested" packages -apt_autoclean: yes # remove .deb files for packages no longer on your system -apt_default_packages: - - python3-apt - - unattended-upgrades - - apt-transport-https - - curl - - ca-certificates - - software-properties-common -apt_default_packages_post20: - - python3-apt -apt_default_packages_pre20: - - python-apt -apt_release: jammy # What release to pull from \ No newline at end of file +--- +apt_reset_source_list: false # reset the /etc/apt/sources.list to the default +apt_mirror_url: "http://archive.ubuntu.com" # the mirror from where to install packages +apt_cache_valid_time: 3600 # Time (in seconds) the apt cache stays valid +apt_install_recommends: false # whether or not to install the "recommended" packages +apt_install_suggests: false # whether or not to install the "suggested" packages +apt_autoremove: true # remove packages that are no longer needed for dependencies +apt_clean: false # remove all cached .deb files +apt_autoremove_recommends: true # whether to automatically remove "recommended" packages +apt_autoremove_suggests: true # whether to automatically remove "suggested" packages +apt_autoclean: true # remove .deb files for packages no longer on your system +apt_source: false # include apt source repos +apt_upgrade: false # perform some automatic upgrades +apt_upgrade_style: "safe" # or "full" or "dist" +apt_upgrade_frequency: "once" # or "boot" or "always" diff --git a/meta/main.yml b/meta/main.yml index dcb40bb..a8d7583 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,16 +1,21 @@ -# file: apt/meta/main.yml - +--- galaxy_info: - author: pjan vandaele - company: ANXS - description: Manages apt and executes apt-get update to ensure the local APT package cache is up to date. - min_ansible_version: 2.3 - license: MIT + role_name: "apt" + namespace: "anxs" + author: "ANXS Crew" + company: "ANXS" + description: "Manages apt and executes apt-get update to ensure the local APT package cache is up to date." + min_ansible_version: "2.13" + license: "MIT" platforms: - - name: Ubuntu - versions: - - all - categories: - - system - -dependencies: [] + - name: "Ubuntu" + versions: + - "bionic" + - "focal" + - name: "Debian" + versions: + - "trixie" + - "bookworm" + galaxy_tags: + - "system" + - "apt" diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..d35f731 --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,11 @@ +--- +- name: Converge + hosts: all + become: true + gather_facts: true + vars: + apt_upgrade: "{{ lookup('env', 'APT_UPGRADE') | default('false', true) | bool }}" + apt_upgrade_style: "{{ lookup('env', 'APT_UPGRADE_STYLE') | default('safe', true) }}" + apt_upgrade_frequency: "{{ lookup('env', 'APT_UPGRADE_FREQUENCY') | default('once', true) }}" + roles: + - role: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | default(playbook_dir + '/../..', true) }}" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..82b03e8 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,47 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: "anxs-apt-${MOLECULE_OS:-debian}-${MOLECULE_VERSION:-12}-${APT_UPGRADE:-false}-${APT_UPGRADE_STYLE:-safe}-${APT_UPGRADE_FREQUENCY:-once}" + image: "${MOLECULE_IMAGE:-geerlingguy/docker-debian12-ansible:latest}" + privileged: true + pre_build_image: true + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible/tmp + playbooks: + converge: converge.yml + env: + ANSIBLE_ROLES_PATH: "${MOLECULE_PROJECT_DIRECTORY}/../../..:${MOLECULE_PROJECT_DIRECTORY}/..:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles" + APT_UPGRADE: "${APT_UPGRADE:-false}" + APT_UPGRADE_STYLE: "${APT_UPGRADE_STYLE:-safe}" + APT_UPGRADE_FREQUENCY: "${APT_UPGRADE_FREQUENCY:-once}" + +verifier: + name: testinfra + directory: tests + env: + APT_UPGRADE: "${APT_UPGRADE:-false}" + APT_UPGRADE_FREQUENCY: "${APT_UPGRADE_FREQUENCY:-once}" + +scenario: + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - converge + - idempotence + - verify + - destroy diff --git a/molecule/default/requirements.yml b/molecule/default/requirements.yml new file mode 100644 index 0000000..2895da6 --- /dev/null +++ b/molecule/default/requirements.yml @@ -0,0 +1,2 @@ +--- +- name: ANXS.python diff --git a/molecule/default/tests/test_apt.py b/molecule/default/tests/test_apt.py new file mode 100644 index 0000000..62f241b --- /dev/null +++ b/molecule/default/tests/test_apt.py @@ -0,0 +1,70 @@ +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ.get('MOLECULE_INVENTORY_FILE')).get_hosts('all') + + +def test_apt_conf_file(host): + f = host.file('/etc/apt/apt.conf.d/10general') + assert f.exists + assert f.user == 'root' + assert f.group == 'root' + assert f.mode in (0o644, 0o640) + + +def test_default_packages_installed(host): + packages = ['apt-transport-https', 'ca-certificates'] + for pkg in packages: + p = host.package(pkg) + assert p.is_installed + + +def test_apt_update_cached(host): + cmd = host.run('apt-cache policy') + assert cmd.rc == 0 + + +def test_sources_list_or_directory(host): + """Test that apt sources are configured (either classic or deb822 format).""" + # Debian 12+ uses /etc/apt/sources.list.d/ with .sources files + # Older systems use /etc/apt/sources.list + sources_file = host.file('/etc/apt/sources.list') + sources_dir = host.file('/etc/apt/sources.list.d') + + # At least one method should exist + assert sources_file.exists or sources_dir.is_directory + + +def test_upgrade_locks(host): + """Test upgrade lock files based on environment configuration.""" + upgrade_enabled = os.environ.get('APT_UPGRADE', 'false').lower() == 'true' + upgrade_frequency = os.environ.get('APT_UPGRADE_FREQUENCY', 'once') + + # If upgrades are explicitly disabled, ensure no lock files were created. + if not upgrade_enabled: + assert not host.file('/var/cache/anxs/apt-upgrade').exists + assert not host.file('/var/run/anxs-apt-upgrade').exists + return + + # When upgrade is enabled, check lock file behavior based on frequency + if upgrade_frequency == 'once': + # Should have created persistent lock file + lock_file = host.file('/var/cache/anxs/apt-upgrade') + assert lock_file.exists, "Expected lock file for 'once' frequency" + assert lock_file.is_file + # Should not have boot lock + assert not host.file('/var/run/anxs-apt-upgrade').exists + + elif upgrade_frequency == 'boot': + # Should have created boot-time lock file + lock_file = host.file('/var/run/anxs-apt-upgrade') + assert lock_file.exists, "Expected lock file for 'boot' frequency" + assert lock_file.is_file + # Should not have persistent lock + assert not host.file('/var/cache/anxs/apt-upgrade').exists + + elif upgrade_frequency == 'always': + # No lock files for 'always' (runs every time) + assert not host.file('/var/cache/anxs/apt-upgrade').exists + assert not host.file('/var/run/anxs-apt-upgrade').exists diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..fa86f2c --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,22 @@ +# Core testing framework +molecule>=25.9.0 +molecule-plugins[docker]>=23.5.0 + +# Ansible ecosystem +ansible>=8.0.0 +ansible-lint>=6.22.0 + +# Python testing +pytest>=7.4.0 +pytest-testinfra>=10.2.0 + +# Code quality +yamllint>=1.35.0 +flake8>=6.0.0 +black>=23.0.0 + +# Docker support +docker>=6.1.0 + +# Network utilities (for some molecule scenarios) +netaddr>=0.10.0 diff --git a/tasks/main.yml b/tasks/main.yml index 7407111..2616148 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,59 +1,129 @@ -# file: apt/tasks/main.yml - -- name: APT | Reset the sources list (/etc/apt/sources.list) - template: - src: etc_apt_sources.list.j2 - dest: /etc/apt/sources.list - owner: root - group: root - mode: 0644 +--- +- name: "Check if fuser is available" + ansible.builtin.command: which fuser + register: apt_fuser_check + failed_when: false + changed_when: false + +- name: "Wait until frontend lock file is not being held" + ansible.builtin.command: fuser /var/lib/dpkg/lock-frontend + register: apt_lock_result + failed_when: false + changed_when: false + retries: 60 + delay: 5 + until: apt_lock_result.rc == 1 + when: apt_fuser_check.rc == 0 + +- name: "Reset the sources list (/etc/apt/sources.list)" + ansible.builtin.template: + src: "etc_apt_sources.list.j2" + dest: "/etc/apt/sources.list" + owner: "root" + group: "root" + mode: "0644" when: apt_reset_source_list -- name: APT | Update the apt cache - apt: - update_cache: yes - cache_valid_time: "{{apt_cache_valid_time}}" +- name: "Update the apt cache" + ansible.builtin.apt: + update_cache: true + cache_valid_time: "{{ apt_cache_valid_time }}" + +- name: "Check if we ever upgraded" + ansible.builtin.stat: + path: "{{ apt_upgrade_lock_once }}" + register: apt_upgrade_once_results + when: apt_upgrade_frequency == "once" + +- name: "Check if we upgraded this boot" + ansible.builtin.stat: + path: "{{ apt_upgrade_lock_boot }}" + register: apt_upgrade_boot_results + when: apt_upgrade_frequency == "boot" + +- name: "Upgrade packages" + ansible.builtin.apt: + upgrade: "{{ apt_upgrade_style }}" + when: >- + apt_upgrade + and (apt_upgrade_frequency == "always" + or (apt_upgrade_frequency == "boot" and not + (apt_upgrade_boot_results | default(apt_upgrade_fake)).stat.exists) + or (apt_upgrade_frequency == "once" and not + (apt_upgrade_once_results | default(apt_upgrade_fake)).stat.exists)) + register: apt_upgrade_results -- name: APT | Remove packages that are no longer needed for dependencies - apt: - autoremove: "yes" +- name: "Create anxs cache directory" + ansible.builtin.file: + path: "/var/cache/anxs" + state: "directory" + owner: "root" + group: "root" + mode: '0755' + when: + - apt_upgrade + - apt_upgrade_frequency == "once" + - apt_upgrade_results is defined + - not apt_upgrade_results is skipped + +- name: "Note that apt upgrade happened once" + ansible.builtin.file: + path: "{{ apt_upgrade_lock_once }}" + state: "touch" + mode: '0644' + when: + - apt_upgrade + - apt_upgrade_frequency == "once" + - apt_upgrade_results is defined + - not apt_upgrade_results is skipped + +- name: "Note that apt upgrade happened this boot" + ansible.builtin.file: + path: "{{ apt_upgrade_lock_boot }}" + state: "touch" + mode: '0644' + when: + - apt_upgrade + - apt_upgrade_frequency == "boot" + - apt_upgrade_results is defined + - not apt_upgrade_results is skipped + +- name: "Remove packages that are no longer needed for dependencies" + ansible.builtin.apt: + autoremove: true when: apt_autoremove -- name: APT | Remove .deb files for packages no longer on your system - apt: - autoclean: "yes" +- name: "Remove .deb files for packages no longer on your system" + ansible.builtin.apt: + autoclean: true when: apt_autoclean -- name: APT | Check for cached .deb files - shell: "ls /var/cache/apt/archives/*.deb 2&> /dev/null | wc -l" +- name: "Check for cached .deb files" + ansible.builtin.find: + paths: /var/cache/apt/archives + patterns: "*.deb" + file_type: file + recurse: false register: apt_cache_check - changed_when: no + changed_when: false when: apt_clean -- name: APT | Remove all cached .deb files - shell: apt-get -y clean - changed_when: apt_cache_check.stdout != "0" - when: apt_clean and apt_cache_check.stdout != "0" - -- name: APT | Update the general configuration (/etc/apt/apt.conf.d/10general) - template: - src: etc_apt_apt.conf.d_10general.j2 - dest: /etc/apt/apt.conf.d/10general - owner: root - group: root - mode: 0644 - -- name: APT | Make sure the required packages are installed 20.04 and above - set_fact: - apt_packages_list: "{{ apt_default_packages | union (apt_default_packages_post20) | unique }}" - when: ansible_facts['distribution_version'] is version('20.04', '>=') - -- name: APT | Make sure the required packages are installed 19.10 and below - set_fact: - apt_packages_list: "{{ apt_default_packages | union (apt_default_packages_pre20) | unique }}" - when: ansible_facts['distribution_version'] is version('20.04', '<') - -- name: APT | Install Packages - apt: - pkg: "{{apt_packages_list}}" - state: present +- name: "Remove all cached .deb files" + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: "{{ apt_cache_check.files | default([]) }}" + when: apt_clean and (apt_cache_check.matched | default(0)) > 0 + +- name: "Update the general configuration (/etc/apt/apt.conf.d/10general)" + ansible.builtin.template: + src: "etc_apt_apt.conf.d_10general.j2" + dest: "/etc/apt/apt.conf.d/10general" + owner: "root" + group: "root" + mode: "0644" + +- name: "Make sure the required packages are installed" + ansible.builtin.apt: + name: "{{ apt_default_packages }}" + state: "present" diff --git a/templates/etc_apt_sources.list.j2 b/templates/etc_apt_sources.list.j2 index 860d9dd..2fea267 100644 --- a/templates/etc_apt_sources.list.j2 +++ b/templates/etc_apt_sources.list.j2 @@ -1,20 +1,21 @@ -# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to -# newer versions of the distribution. -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} main restricted -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} main restricted +# {{ansible_managed}} +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} main restricted +{% if apt_source %} +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} main restricted +{% endif %} ## Major bug fix updates produced after the final release of the ## distribution. -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates main restricted -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates main restricted +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates main restricted +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates main restricted ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team. Also, please note that software in universe WILL NOT receive any ## review or updates from the Ubuntu security team. -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} universe -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} universe -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates universe -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates universe +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} universe +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} universe +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates universe +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates universe ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to @@ -22,36 +23,36 @@ deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates universe ## multiverse WILL NOT receive any review or updates from the Ubuntu ## security team. -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} multiverse -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }} multiverse -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates multiverse -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-updates multiverse +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} multiverse +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }} multiverse +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates multiverse +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-updates multiverse ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. -deb {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-backports main restricted universe multiverse -deb-src {{ apt_mirror_url }}/ubuntu/ {{ apt_release }}-backports main restricted universe multiverse +deb {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-backports main restricted universe multiverse +deb-src {{ apt_mirror_url }}/ubuntu/ {{ ansible_distribution_release }}-backports main restricted universe multiverse -deb http://security.ubuntu.com/ubuntu {{ apt_release }}-security main restricted -deb-src http://security.ubuntu.com/ubuntu {{ apt_release }}-security main restricted -deb http://security.ubuntu.com/ubuntu {{ apt_release }}-security universe -deb-src http://security.ubuntu.com/ubuntu {{ apt_release }}-security universe -deb http://security.ubuntu.com/ubuntu {{ apt_release }}-security multiverse -deb-src http://security.ubuntu.com/ubuntu {{ apt_release }}-security multiverse +deb http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security main restricted +deb-src http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security main restricted +deb http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security universe +deb-src http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security universe +deb http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security multiverse +deb-src http://security.ubuntu.com/ubuntu {{ ansible_distribution_release }}-security multiverse ## Uncomment the following two lines to add software from Canonical's ## 'partner' repository. ## This software is not part of Ubuntu, but is offered by Canonical and the ## respective vendors as a service to Ubuntu users. -# deb http://archive.canonical.com/ubuntu {{ apt_release }} partner -# deb-src http://archive.canonical.com/ubuntu {{ apt_release }} partner +# deb http://archive.canonical.com/ubuntu {{ ansible_distribution_release }} partner +# deb-src http://archive.canonical.com/ubuntu {{ ansible_distribution_release }} partner ## Uncomment the following two lines to add software from Ubuntu's ## 'extras' repository. ## This software is not part of Ubuntu, but is offered by third-party ## developers who want to ship their latest software. -# deb http://extras.ubuntu.com/ubuntu {{ apt_release }} main -# deb-src http://extras.ubuntu.com/ubuntu {{ apt_release }} main +# deb http://extras.ubuntu.com/ubuntu {{ ansible_distribution_release }} main +# deb-src http://extras.ubuntu.com/ubuntu {{ ansible_distribution_release }} main diff --git a/test.yml b/test.yml deleted file mode 100644 index f364983..0000000 --- a/test.yml +++ /dev/null @@ -1,5 +0,0 @@ -- hosts: all - vars_files: - - 'defaults/main.yml' - tasks: - - include: 'tasks/main.yml' diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..7c9de16 --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,15 @@ +--- +apt_default_packages: + - "python3-apt" + - "unattended-upgrades" + - "apt-transport-https" + - "curl" + - "ca-certificates" + - "software-properties-common" + - "python3-debian" + +apt_upgrade_lock_boot: "/var/run/anxs-apt-upgrade" +apt_upgrade_lock_once: "/var/cache/anxs/apt-upgrade" +apt_upgrade_fake: + stat: + exists: false