Changeset - 5f9f8aef3473
[Not reviewed]
5 11 1
Branko Majic (branko) - 22 months ago 2024-02-10 23:58:28
branko@majic.rs
MAR-154: Drop support for Python 2.7 from the common role:

- This primarily concerns removal of pip requirements upgrade checks
for Python 2.7.
- The old Python 3-specific paths are getting deprecated, and the
Python 2 paths will be used instead.
- Set permissions on pipreqcheck directory explicitly (because of
deprecation testing).
17 files changed with 150 insertions and 212 deletions:
0 comments (0 inline, 0 general)
docs/releasenotes.rst
Show inline comments
 
@@ -4,24 +4,38 @@ Release notes
 

	
 
x.y.z
 
-----
 

	
 
Dropped support for Debian 10 (Buster).
 

	
 
**Breaking changes:**
 

	
 
* All roles
 

	
 
  * Dropped support for Debian 10 (Buster).
 

	
 
* ``common`` role
 

	
 
  * Dropped support for Python 2.7 pip requirements upgrade
 
    checks. Only Python 3 is supported now.
 

	
 
    Requirements (input) files for Python 3 are now put under the
 
    ``/etc/pip_check_requirements_upgrades`` directory instead of
 
    ``/etc/pip_check_requirements_upgrades-py3``.
 

	
 
    The ``pip_check_requirements_py3`` /
 
    ``pip_check_requirements_py3_in`` role parameters have been
 
    renamed to ``pip_check_requirements`` /
 
    ``pip_check_requirements_in``.
 

	
 
**Bug fixes:**
 

	
 
* ``common`` role
 

	
 
  * Fix deprecation warnings for Python requirements upgrade checks
 
    when using pip-tools 7.3.0. This would result in unnecessary
 
    notifications being sent out to server administrator.
 

	
 

	
 
7.1.0
 
-----
 

	
docs/rolereference.rst
Show inline comments
 
@@ -263,41 +263,39 @@ The role implements the following:
 
  pacakges and (new) TCP connections. The rate-limitting is based on the source
 
  IP address, using the ``iptables hashlimit`` module.
 
* Sets-up system for performing checks on certificates (currently only if they
 
  expire within less than 30 days). Roles that want their certificates checked
 
  should deploy a ``.conf`` to directory ``/etc/check_certificate/`` with paths
 
  to certificate files, one per line. Certificates are checked on
 
  daily basis, using crontab (resulting in failures being sent out to
 
  the ``root`` user).
 
* Deploys ``apticron`` package that performs checks for available package
 
  upgrades on daily basis. Mails are delivered to local ``root`` account, and
 
  can be redirected elsewhere via aliases. If using ``mail_forwarder`` or
 
  ``mail_server`` roles on the same server, aliases can be set-up through them.
 
* Sets-up system for performing checks on pip requirements
 
  files. Roles that want their requirements files checked should
 
  create a sub-directory inside of
 
  ``/etc/pip_check_requirements_upgrades`` (for Python 2
 
  applications), or ``/etc/pip_check_requirements_upgrades-py3`` (for
 
  Python 3 applications), and place ``.txt`` and ``.in`` files inside
 
  (with same base name). The ``.txt`` files should be standard
 
  requirements files with fixed versions (the ones installed by the
 
  role). The ``.in`` files should contain only the top-level packages
 
  (no dependencies). Avoid hard-coding versions in the ``.in`` file
 
  unless really needed. For packages where you want to stick to
 
  stable/LTS version branch, you should be able to use ``~=`` operator
 
  (for example ``django~=1.8.0``. Checks are implemented via
 
  `pip-tools <https://github.com/jazzband/pip-tools>`_ and a custom
 
  script that outputs diffs if upgrades are available. Script is run
 
  via cronjob on daily basis, and any output will be delivered to
 
  local ``root`` user.
 
* Sets-up system for performing checks on pip requirements files. Only
 
  Python 3 is supported. Roles that want their requirements files
 
  checked should create a sub-directory inside of
 
  ``/etc/pip_check_requirements_upgrades``, and place ``.txt`` and
 
  ``.in`` files inside (with same base name). The ``.txt`` files
 
  should be standard requirements files with fixed versions (the ones
 
  installed by the role). The ``.in`` files should contain only the
 
  top-level packages (no dependencies). Avoid hard-coding versions in
 
  the ``.in`` file unless really needed. For packages where you want
 
  to stick to stable/LTS version branch, you should be able to use
 
  ``~=`` operator (for example ``django~=1.8.0``. Checks are
 
  implemented via `pip-tools <https://github.com/jazzband/pip-tools>`_
 
  and a custom script that outputs diffs if upgrades are
 
  available. Script is run via cronjob on daily basis, and any output
 
  will be delivered to local ``root`` user.
 
* Optionally configures time synchronisation using NTP (if
 
  ``ntp_servers`` parameter is set).
 

	
 

	
 
Role dependencies
 
~~~~~~~~~~~~~~~~~
 

	
 
Depends on the following roles:
 

	
 
* **backup_client**
 

	
 

	
 
@@ -408,50 +406,34 @@ Parameters
 
  machine using NTP. If no time synchronisation should be set-up, set
 
  to empty list. Default is not to configure time synchronisation.
 

	
 
  If setting this parameter, it is recommended to set the list of
 
  servers to list shipped by default Debian configuration::
 

	
 
    - "0.debian.pool.ntp.org"
 
    - "1.debian.pool.ntp.org"
 
    - "2.debian.pool.ntp.org"
 
    - "3.debian.pool.ntp.org"
 

	
 
**pip_check_requirements_in** (list, optional, ``[pip, pip-tools, setuptools, wheel]``)
 
  List of Python package requirements inputs to use for checking for
 
  package upgrades for the Python 2 virtual environment used to run
 
  the check itself. For Python 3, see the dedicated parameter
 
  ``pip_check_requirements_py3`` below.
 

	
 
**pip_check_requirements** (list, optional, ``[click==7.1.2, pip-tools==5.5.0, pip==20.3.4, setuptools==44.1.1, wheel==0.37.1]``)
 
  List of Python package requirements to install in Python 2 virtual
 
  environment in order to be able to run the ``pip-tools``
 
  applications as part of pip requirements upgrade checks. This list
 
  needs to be updated from time to time as the new releases of
 
  ``pip-tools`` and related packages are coming out. For Python 3, see
 
  the dedicated parameter ``pip_check_requirements_py3`` below.
 

	
 
**pip_check_requirements_py3_in** (list, optional, ``[pip, pip-tools, setuptools, wheel]``)
 
  List of Python package requirements inputs to use for checking for
 
  package upgrades for the Python 3 virtual environment used to run
 
  the check itself. For Python 2, see the dedicated parameter
 
  ``pip_check_requirements`` above.
 
  the check itself.
 

	
 
**pip_check_requirements_py3** (list, optional, ``see below``)
 
**pip_check_requirements** (list, optional, ``see below``)
 
  List of Python package requirements to install in Python 3 virtual
 
  environment in order to be able to run the ``pip-tools``
 
  applications as part of pip requirements upgrade checks. This list
 
  needs to be updated from time to time as the new releases of
 
  ``pip-tools`` and related packages are coming out. For Python 2, see
 
  the dedicated parameter ``pip_check_requirements`` above.
 
  ``pip-tools`` and related packages are coming out.
 

	
 
  Default value is:
 

	
 
  .. code-block:: yaml
 

	
 
    - build==1.0.3
 
    - click==8.1.7
 
    - importlib-metadata==6.7.0
 
    - packaging==23.2
 
    - pip-tools==6.14.0
 
    - pip==23.1.2
 
    - pyproject-hooks==1.0.0
docs/usage.rst
Show inline comments
 
@@ -2555,38 +2555,36 @@ No packages will be upgraded automatically - ensuring you can make sure upgrades
 
work correctly and do not cause major outage without anyone being present to
 
fix them.
 

	
 
Another useful package you may want to look into is ``needrestart`` - which runs
 
as a hook during the upgrade process to detect any processes that seem to be
 
running with outdated libraries, allowing you to restart them as well. This
 
package is *not* installed by the ``common`` role out-of-the-box, but you can
 
easily do so by updating the ``common_packages`` setting.
 

	
 
In addition to system packages, the ``common`` role makes it easy to check if
 
any of the pip requirements files are outdated as well. It should be noted,
 
though, that this check does *not* verify the Python virtual environments
 
themselves.
 
themselves. Only Python 3 is supported at this time.
 

	
 
This is primarily useful when you use `pip-tools
 
<https://github.com/jazzband/pip-tools>`_ for maintaining the
 
requirements files. In fact, I would encourage you to utilise
 
``pip-tools`` for both this purpose and for keeping the virtual
 
environment in sync and up-to-date.
 

	
 
Roles that want to take advantage of this would:
 

	
 
- Create a sub-directory under
 
  ``/etc/pip_check_requirements_upgrades/`` (for Python 2
 
  applications) or ``/etc/pip_check_requirements_upgrades-py3/`` (for
 
  Python 3 applications).
 
  ``/etc/pip_check_requirements_upgrades/``.
 
- Deploy ``.in`` and ``.txt`` files within the sub-directory (see ``pip-tools``
 
  docs for explanation of how the ``.in`` files work).
 
- Ensure the created sub-directory and files have ownership set to
 
  ``root:pipreqcheck``.
 

	
 
.. note::
 
   If you are using the ``wsgi_website`` role as dependency, simply set-up the
 
   ``wsgi_requirements`` parameter, and then deploy the ``.in`` and ``.txt``
 
   file into directory ``/etc/pip_check_requirements_upgrades/FQDN`` (this
 
   directory is automatically created when ``wsgi_requirements`` is specified).
 

	
 

	
roles/common/defaults/main.yml
Show inline comments
 
@@ -9,35 +9,24 @@ incoming_connection_limit: 3/second
 
incoming_connection_limit_burst: 9
 
prompt_colour: none
 
prompt_id: null
 
extra_backup_patterns:
 
  - "/root"
 
  - "/home"
 
pip_check_requirements_in:
 
  - pip
 
  - pip-tools
 
  - setuptools
 
  - wheel
 
pip_check_requirements:
 
  - click==7.1.2
 
  - pip-tools==5.5.0
 
  - pip==20.3.4
 
  - setuptools==44.1.1
 
  - wheel==0.37.1
 
pip_check_requirements_py3_in:
 
  - pip
 
  - pip-tools
 
  - setuptools
 
  - wheel
 
pip_check_requirements_py3:
 
  - build==1.0.3
 
  - click==8.1.7
 
  - importlib-metadata==6.7.0
 
  - packaging==23.2
 
  - pip-tools==6.14.0
 
  - pip==23.1.2
 
  - pyproject-hooks==1.0.0
 
  - setuptools==68.0.0
 
  - tomli==2.0.1
 
  - typing-extensions==4.7.1
 
  - wheel==0.41.3
 
  - zipp==3.15.0
roles/common/files/cron_check_pip_requirements-py3
Show inline comments
 
deleted file
roles/common/molecule/default/files/pip_check_requirements_upgrades-py3/with_updates/requirements.in
Show inline comments
 
deleted file
roles/common/molecule/default/files/pip_check_requirements_upgrades-py3/with_updates/requirements.txt
Show inline comments
 
deleted file
roles/common/molecule/default/files/pip_check_requirements_upgrades-py3/without_updates/requirements.in
Show inline comments
 
deleted file
roles/common/molecule/default/files/pip_check_requirements_upgrades-py3/without_updates/requirements.txt
Show inline comments
 
deleted file
roles/common/molecule/default/group_vars/parameters-optional.yml
Show inline comments
 
@@ -45,29 +45,24 @@ pipreqcheck_gid: 2500
 
prompt_colour: cyan
 
prompt_id: test
 
# Purposefully set this to 3 servers to make sure we are
 
# overriding the default configuration.
 
ntp_servers:
 
  - "0.debian.pool.ntp.org"
 
  - "1.debian.pool.ntp.org"
 
  - "2.debian.pool.ntp.org"
 
maintenance: true
 
maintenance_allowed_hosts:
 
  - client1
 
pip_check_requirements_in:
 
  - pip >= 0.2.1
 
  - pip-tools >= 0.2.2
 
  - setuptools >= 0.2.3
 
  - wheel >= 0.2.4
 
pip_check_requirements_py3_in:
 
  - pip >= 0.3.1
 
  - pip-tools >= 0.3.2
 
  - setuptools >= 0.3.3
 
  - wheel >= 0.3.4
 

	
 
# From backup_client role meta dependency.
 
backup_encryption_key: "{{ lookup('file', 'tests/data/gnupg/backup_encryption_key') }}"
 
backup_server: backup-server
 
backup_server_host_ssh_public_keys:
 
  - bougs-backup-server-key-1
 
  - bougs-backup-server-key-2
 
backup_ssh_key: "bogus-backup-client-key"
roles/common/molecule/default/playbook.yml
Show inline comments
 
@@ -11,45 +11,38 @@
 

	
 
    - name: Set-up directories for testing pip requirements upgrade checks script
 
      file:
 
        path: "{{ item }}"
 
        state: directory
 
        owner: root
 
        group: pipreqcheck
 
        mode: 0750
 
      with_items:
 
        - "/tmp/pip_check_requirements_upgrades"
 
        - "/tmp/pip_check_requirements_upgrades/with_updates"
 
        - "/tmp/pip_check_requirements_upgrades/without_updates"
 
        - "/tmp/pip_check_requirements_upgrades-py3"
 
        - "/tmp/pip_check_requirements_upgrades-py3/with_updates"
 
        - "/tmp/pip_check_requirements_upgrades-py3/without_updates"
 

	
 
    - name: Deploy files for testing pip requirements upgrade checks script
 
      copy:
 
        src: "{{ item }}"
 
        dest: "/tmp/{{ item }}"
 
        owner: root
 
        group: pipreqcheck
 
        mode: 0640
 
        directory_mode: 0750
 
      with_items:
 
        - "pip_check_requirements_upgrades/with_updates/requirements.in"
 
        - "pip_check_requirements_upgrades/with_updates/requirements.txt"
 
        - "pip_check_requirements_upgrades/without_updates/requirements.in"
 
        - "pip_check_requirements_upgrades/without_updates/requirements.txt"
 
        - "pip_check_requirements_upgrades-py3/with_updates/requirements.in"
 
        - "pip_check_requirements_upgrades-py3/with_updates/requirements.txt"
 
        - "pip_check_requirements_upgrades-py3/without_updates/requirements.in"
 
        - "pip_check_requirements_upgrades-py3/without_updates/requirements.txt"
 

	
 
    - name: Install web server for testing connectivity
 
      apt:
 
        name: nginx
 
        state: present
 

	
 
    - name: Deploy firewall configuration file for the web server
 
      copy:
 
        src: ferm_http.conf
 
        dest: /etc/ferm/conf.d/99-http.conf
 
        owner: root
 
        group: root
roles/common/molecule/default/prepare.yml
Show inline comments
 
@@ -120,20 +120,44 @@
 
        - security
 
        - raw
 

	
 
    - name: Create some custom legacy ip6tables chains for testing their removal (max chain name length is 29)
 
      command: "ip6tables-legacy -t '{{ item }}' -N '{{ (ansible_date_time.iso8601_micro | to_uuid)[:28] }}'"
 
      with_items:
 
        - filter
 
        - nat
 
        - mangle
 
        - security
 
        - raw
 

	
 
    - name: Create deprecated directory for storing requirements files created using Python 3 (pip requirements upgrade checks)
 
      file:
 
        path: "/etc/pip_check_requirements_upgrades-py3"
 
        state: directory
 
        owner: root
 
        group: root
 
        mode: 0750
 

	
 
    - name: Create deprecated directory for Python 3 virtual environment (pip requirements upgrade checks)
 
      file:
 
        path: "/var/lib/pipreqcheck/virtualenv-py3/"
 
        state: directory
 
        owner: root
 
        group: root
 
        mode: 0750
 

	
 
    - name: Create deprecated cronjob file for Python 3 (pip requirements upgrade checks)
 
      file:
 
        path: "/etc/cron.d/check_pip_requirements-py3"
 
        state: touch
 
        owner: root
 
        group: root
 
        mode: 0644
 

	
 
- hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Remove the ss utility (see https://github.com/philpep/testinfra/pull/320)
 
      file:
 
        path: "/bin/ss"
 
        state: absent
roles/common/molecule/default/tests/test_default.py
Show inline comments
 
@@ -225,121 +225,108 @@ def test_check_certificate_crontab(host):
 
    Tests deployment of cron job for checking certificates.
 
    """
 

	
 
    check_certificate_crontab = host.file('/etc/cron.d/check_certificate')
 

	
 
    assert check_certificate_crontab.is_file
 
    assert check_certificate_crontab.user == 'root'
 
    assert check_certificate_crontab.group == 'root'
 
    assert check_certificate_crontab.mode == 0o644
 
    assert "0 0 * * * nobody /usr/local/bin/check_certificate.sh -q expiration" in check_certificate_crontab.content_string
 

	
 

	
 
@pytest.mark.parametrize('virtualenv_activate_path', [
 
    '/var/lib/pipreqcheck/virtualenv/bin/activate',
 
    '/var/lib/pipreqcheck/virtualenv-py3/bin/activate',
 
])
 
def test_pipreqcheck_virtualenv(host, virtualenv_activate_path):
 
def test_pipreqcheck_virtualenv(host):
 
    """
 
    Tests creation of Python virtual environment used for performing pip
 
    requirements upgrade checks.
 
    """
 

	
 
    virtualenv_activate_path = '/var/lib/pipreqcheck/virtualenv/bin/activate'
 

	
 
    with host.sudo():
 
        virtualenv_activate = host.file(virtualenv_activate_path)
 

	
 
        assert virtualenv_activate.is_file
 
        assert virtualenv_activate.user == 'pipreqcheck'
 
        assert virtualenv_activate.group == 'pipreqcheck'
 
        assert virtualenv_activate.mode == 0o644
 

	
 

	
 
@pytest.mark.parametrize('config_dir', [
 
    '/etc/pip_check_requirements_upgrades',
 
    '/etc/pip_check_requirements_upgrades-py3',
 
])
 
def test_pipreqcheck_directories(host, config_dir):
 
def test_pipreqcheck_directories(host):
 
    """
 
    Tests creation of directories used for storing configuration used by script
 
    that performs pip requirements upgrade checks.
 
    """
 

	
 
    config_dir = '/etc/pip_check_requirements_upgrades'
 

	
 
    with host.sudo():
 
        pipreqcheck_config_directory = host.file(config_dir)
 
        assert pipreqcheck_config_directory.is_directory
 
        assert pipreqcheck_config_directory.user == 'root'
 
        assert pipreqcheck_config_directory.group == 'pipreqcheck'
 
        assert pipreqcheck_config_directory.mode == 0o750
 

	
 
        pipreqcheck_config_directory_pipreqcheck = host.file(os.path.join(config_dir, 'pipreqcheck'))
 
        assert pipreqcheck_config_directory_pipreqcheck.is_directory
 
        assert pipreqcheck_config_directory_pipreqcheck.user == 'root'
 
        assert pipreqcheck_config_directory_pipreqcheck.group == 'pipreqcheck'
 
        assert pipreqcheck_config_directory_pipreqcheck.mode == 0o750
 

	
 

	
 
@pytest.mark.parametrize('requirements_in_path, requirements_txt_path', [
 
    ('/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in',
 
     '/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt'),
 
    ('/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.in',
 
     '/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.txt'),
 
])
 
def test_pipreqcheck_requirements(host, requirements_in_path, requirements_txt_path):
 
def test_pipreqcheck_requirements(host):
 
    """
 
    Tests deployment of requirements input and text file used for virtual
 
    environment utilised by script that perform pip requirements upgrade checks.
 
    """
 

	
 
    requirements_in_path = '/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in'
 
    requirements_txt_path = '/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt'
 

	
 
    with host.sudo():
 
        requirements_in = host.file(requirements_in_path)
 
        assert requirements_in.is_file
 
        assert requirements_in.user == 'root'
 
        assert requirements_in.group == 'pipreqcheck'
 
        assert requirements_in.mode == 0o640
 

	
 
        requirements_txt = host.file(requirements_txt_path)
 
        requirements_txt.is_file
 
        assert requirements_txt.user == 'root'
 
        assert requirements_txt.group == 'pipreqcheck'
 
        assert requirements_txt.mode == 0o640
 

	
 

	
 
@pytest.mark.parametrize("pip_path, expected_packages",  [
 
    ('/var/lib/pipreqcheck/virtualenv/bin/pip', [
 
        "click==7.1.2",
 
        "pip-tools==5.5.0",
 
        "pip==20.3.4",
 
        "setuptools==44.1.1",
 
        "wheel==0.37.1",
 
    ]),
 
    ('/var/lib/pipreqcheck/virtualenv-py3/bin/pip', [
 
def test_pipreqcheck_virtualenv_packages(host):
 
    """
 
    Tests if correct packages are installed in virtualenv used for pip
 
    requirements checks..
 
    """
 

	
 
    pip_path = '/var/lib/pipreqcheck/virtualenv/bin/pip'
 

	
 
    expected_packages = [
 
        "build==1.0.3",
 
        "click==8.1.7",
 
        "importlib-metadata==6.7.0",
 
        "packaging==23.2",
 
        "pip-tools==6.14.0",
 
        "pip==23.1.2",
 
        "pyproject_hooks==1.0.0",
 
        "setuptools==68.0.0",
 
        "tomli==2.0.1",
 
        "typing_extensions==4.7.1",
 
        "wheel==0.41.3",
 
        "zipp==3.15.0",
 
    ]),
 
])
 
def test_pipreqcheck_virtualenv_packages(host, pip_path, expected_packages):
 
    """
 
    Tests if correct packages are installed in virtualenv used for pip
 
    requirements checks..
 
    """
 
    ]
 

	
 
    packages = host.run("sudo -u pipreqcheck %s freeze --all", pip_path)
 

	
 
    # Normalise package names and order.
 
    expected_packages = sorted([p.lower() for p in expected_packages])
 
    actual_packages = sorted(packages.stdout.lower().strip().split("\n"))
 

	
 
    # This is a dummy distro-provided package ignored by the
 
    # pip-tools. pkg-resources for Python 2.7, pkg_resources for
 
    # Python 3.
 
    if "pkg-resources==0.0.0" in actual_packages:
 
        actual_packages.remove("pkg-resources==0.0.0")
 
@@ -353,92 +340,73 @@ def test_pipreqcheck_script(host):
 
    """
 
    Tests script used for performing pip requirements upgrade checks.
 
    """
 

	
 
    pipreqcheck_script = host.file('/usr/local/bin/pip_check_requirements_upgrades.sh')
 

	
 
    assert pipreqcheck_script.is_file
 
    assert pipreqcheck_script.user == 'root'
 
    assert pipreqcheck_script.group == 'root'
 
    assert pipreqcheck_script.mode == 0o755
 

	
 

	
 
@pytest.mark.parametrize('crontab_path, virtualenv_path', [
 
    ('/etc/cron.d/check_pip_requirements', '/var/lib/pipreqcheck/virtualenv'),
 
    ('/etc/cron.d/check_pip_requirements-py3', '/var/lib/pipreqcheck/virtualenv-py3'),
 
])
 
def test_pipreqcheck_crontab(host, crontab_path, virtualenv_path):
 
def test_pipreqcheck_crontab(host):
 
    """
 
    Tests if crontab entry is set-up correctly for running the pip requirements
 
    upgrade checks.
 
    """
 

	
 
    crontab_path = '/etc/cron.d/check_pip_requirements'
 
    virtualenv_path = '/var/lib/pipreqcheck/virtualenv'
 
    crontab = host.file(crontab_path)
 

	
 
    assert crontab.is_file
 
    assert crontab.user == 'root'
 
    assert crontab.group == 'root'
 
    assert crontab.mode == 0o644
 
    assert "MAILTO=root" in crontab.content_string
 
    assert virtualenv_path in crontab.content_string.split(" ")
 

	
 

	
 
@pytest.mark.parametrize('python_path, expected_major_version', [
 
    ('/var/lib/pipreqcheck/virtualenv/bin/python', '2'),
 
    ('/var/lib/pipreqcheck/virtualenv-py3/bin/python', '3'),
 
])
 
def test_pipreqcheck_virtualenv_python_version(host, python_path, expected_major_version):
 
def test_pipreqcheck_virtualenv_python_version(host):
 
    """
 
    Tests if Python virtual environment for pipreqcheck has been
 
    set-up correctly.
 
    """
 

	
 
    python_path = '/var/lib/pipreqcheck/virtualenv/bin/python'
 
    expected_major_version = '3'
 

	
 
    with host.sudo('pipreqcheck'):
 
        major_version = host.run("%s -c %s", python_path, "import sys; print(sys.version_info.major)")
 

	
 
    assert major_version.rc == 0
 
    assert major_version.stdout.strip() == expected_major_version
 

	
 

	
 
@pytest.mark.parametrize('wrong_python_path', [
 
    '/var/lib/pipreqcheck/virtualenv/bin/python3',
 
    '/var/lib/pipreqcheck/virtualenv-py3/bin/python2.7',
 
])
 
def test_pipreqcheck_virtualenv_wrong_python_version_not_present(host, wrong_python_path):
 
    """
 
    Tests if wrong version of Python 2 is absent or not.
 
    """
 

	
 
    with host.sudo():
 
        wrong_python_path_file = host.file(wrong_python_path)
 

	
 
        assert not wrong_python_path_file.exists
 

	
 

	
 
@pytest.mark.parametrize('environment,config_directory', [
 
    ('/var/lib/pipreqcheck/virtualenv', '/tmp/pip_check_requirements_upgrades'),
 
    ('/var/lib/pipreqcheck/virtualenv-py3', '/tmp/pip_check_requirements_upgrades-py3'),
 
])
 
def test_pipreqcheck_script_output(host, environment, config_directory):
 
def test_pipreqcheck_script_output(host):
 
    """
 
    Tests if the pip_check_requirements_upgrades.sh script properly
 
    reports available updates or not.
 
    """
 

	
 
    virtualenv = '/var/lib/pipreqcheck/virtualenv'
 
    config_directory = '/tmp/pip_check_requirements_upgrades'
 

	
 
    expected_line_count = 9
 
    expected_warning_message = "[WARN]  Upgrades available for: %s/with_updates/requirements.txt" % config_directory
 
    expected_package_diff = "@@ -1 +1 @@\n-urllib3==1.24.2\n+urllib3==1.24.3"
 

	
 
    with host.sudo("pipreqcheck"):
 
        report = host.run("/usr/local/bin/pip_check_requirements_upgrades.sh -q -V %s %s", environment, config_directory)
 
        report = host.run("/usr/local/bin/pip_check_requirements_upgrades.sh -q -V %s %s", virtualenv, config_directory)
 

	
 
        # Clean-up the SSH warning from the beginning of stderr if
 
        # present.
 
        stderr = re.sub("^Warning: Permanently added.*?\r\n", "", report.stderr)
 

	
 
    assert stderr == ""
 
    assert len(report.stdout.split("\n")) == expected_line_count
 
    assert expected_warning_message in report.stdout
 
    assert expected_package_diff in report.stdout
 

	
 

	
 
@pytest.mark.parametrize('default_path', [
roles/common/molecule/default/tests/test_deprecated.py
Show inline comments
 
new file 100644
 
import os
 

	
 
import testinfra.utils.ansible_runner
 

	
 
import pytest
 

	
 

	
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
 
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-*')
 

	
 

	
 
@pytest.mark.parametrize('path', [
 
    '/etc/pip_check_requirements_upgrades-py3/',
 
    '/var/lib/pipreqcheck/virtualenv-py3/',
 
    '/etc/cron.d/check_pip_requirements-py3',
 
])
 
def test_deprecated_paths_are_absent(host, path):
 
    """
 
    Tests if deprecated paths are absent.
 
    """
 

	
 
    with host.sudo():
 
        assert not host.file(path).exists
roles/common/molecule/default/tests/test_parameters_mandatory.py
Show inline comments
 
import os
 
import socket
 

	
 
import paramiko
 

	
 
import testinfra.utils.ansible_runner
 

	
 
import pytest
 

	
 

	
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
 
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-mandatory')
 

	
 

	
 
def test_apt_proxy(host):
 
    """
 
    Tests if proxy configuration for apt is missing.
 
    """
 

	
 
    assert not host.file('/etc/apt/apt.conf.d/00proxy').exists
 

	
 
@@ -126,40 +124,34 @@ def test_ntp_software_not_installed(host):
 
    assert not host.package('ntp').is_installed
 
    assert not host.package('ntpdate').is_installed
 

	
 

	
 
def test_ntp_listening_interfaces(host):
 
    """
 
    Tests if NTP server is not listening.
 
    """
 

	
 
    assert not host.socket('udp://:::123').is_listening
 

	
 

	
 
@pytest.mark.parametrize("requirements_path, expected_requirements", [
 
    ('/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in', [
 
        "pip",
 
        "pip-tools",
 
        "setuptools",
 
        "wheel"
 
    ]),
 
    ('/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.in', [
 
        "pip",
 
        "pip-tools",
 
        "setuptools",
 
        "wheel"
 
    ])
 
])
 
def test_pipreqcheck_input_content(host, requirements_path, expected_requirements):
 
def test_pipreqcheck_input_content(host):
 
    """
 
    Tests content of requirements input file used for virtual
 
    environment utilised by script that performs pip requirements
 
    upgrade checks.
 
    """
 

	
 
    requirements_path = '/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in'
 
    expected_requirements = [
 
        "pip",
 
        "pip-tools",
 
        "setuptools",
 
        "wheel"
 
    ]
 

	
 
    with host.sudo():
 
        deployed_requirements = host.file(requirements_path).content_string
 

	
 
        expected_requirements = sorted([line.lower() for line in expected_requirements])
 
        actual_requirements = sorted(deployed_requirements.lower().strip().split("\n"))
 

	
 
        assert actual_requirements == expected_requirements
roles/common/molecule/default/tests/test_parameters_optional.py
Show inline comments
 
@@ -316,40 +316,34 @@ def test_ntp_query_server_count(host):
 
    assert ntpq.rc == 0
 
    assert len(ntpq.stdout.strip().split("\n")) == expected_stdout_line_count
 

	
 

	
 
def test_ntp_listening_interfaces(host):
 
    """
 
    Tests if NTP server is listening on correct ports.
 
    """
 

	
 
    assert host.socket('udp://:::123').is_listening
 

	
 

	
 
@pytest.mark.parametrize("requirements_path, expected_requirements", [
 
    ('/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in', [
 
        "pip >= 0.2.1",
 
        "pip-tools >= 0.2.2",
 
        "setuptools >= 0.2.3",
 
        "wheel >= 0.2.4"
 
    ]),
 
    ('/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.in', [
 
        "pip >= 0.3.1",
 
        "pip-tools >= 0.3.2",
 
        "setuptools >= 0.3.3",
 
        "wheel >= 0.3.4"
 
    ])
 
])
 
def test_pipreqcheck_input_content(host, requirements_path, expected_requirements):
 
def test_pipreqcheck_input_content(host):
 
    """
 
    Tests content of requirements input file used for virtual
 
    environment utilised by script that performs pip requirements
 
    upgrade checks.
 
    """
 

	
 
    requirements_path = '/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in'
 
    expected_requirements = [
 
        "pip >= 0.3.1",
 
        "pip-tools >= 0.3.2",
 
        "setuptools >= 0.3.3",
 
        "wheel >= 0.3.4"
 
    ]
 

	
 
    with host.sudo():
 
        deployed_requirements = host.file(requirements_path).content_string
 

	
 
        expected_requirements = sorted([line.lower() for line in expected_requirements])
 
        actual_requirements = sorted(deployed_requirements.lower().strip().split("\n"))
 

	
 
        assert actual_requirements == expected_requirements
roles/common/tasks/main.yml
Show inline comments
 
---
 

	
 
# Deprecation
 
# ===========
 

	
 
- name: Drop deprecated directories and files
 
  file:
 
    path: "{{ item }}"
 
    state: absent
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades-py3"
 
    - "/var/lib/pipreqcheck/virtualenv-py3"
 
    - "/etc/cron.d/check_pip_requirements-py3"
 

	
 
# Main implementation
 
# ===================
 

	
 
- name: Enable use of proxy for retrieving system packages via apt
 
  template:
 
    src: "apt_proxy.j2"
 
    dest: "/etc/apt/apt.conf.d/00proxy"
 
    owner: root
 
    group: root
 
    mode: 0644
 
  when: apt_proxy is defined
 

	
 
- name: Disable use of proxy for retrieving system packages via apt
 
  file:
 
    path: "/etc/apt/apt.conf.d/00proxy"
 
@@ -316,166 +331,135 @@
 
- name: Create user for running pip requirements checks
 
  user:
 
    name: "pipreqcheck"
 
    uid: "{{ pipreqcheck_uid | default(omit) }}"
 
    group: "pipreqcheck"
 
    home: "/var/lib/pipreqcheck"
 
    state: present
 

	
 
- name: Check for presence of wrong Python versions
 
  stat:
 
    path: "{{ item.offending_binary }}"
 
  with_items:
 
    - offending_binary: "/var/lib/pipreqcheck/virtualenv/bin/python3"
 
    - offending_binary: "/var/lib/pipreqcheck/virtualenv/bin/python2"
 
      virtualenv_directory: "/var/lib/pipreqcheck/virtualenv"
 
    - offending_binary: "/var/lib/pipreqcheck/virtualenv-py3/bin/python2"
 
      virtualenv_directory: "/var/lib/pipreqcheck/virtualenv-py3"
 
  register: "pipreqcheck_wrong_python_version_check"
 

	
 
- name: Drop Python virtual environment if wrong Python version has been detected within
 
  file:
 
    path: "{{ item.item.virtualenv_directory }}"
 
    state: absent
 
  when: "item.stat.exists"
 
  with_items: "{{ pipreqcheck_wrong_python_version_check.results }}"
 

	
 
- name: Create directory for Python virtual environment used for installing/running pip-tools
 
  file:
 
    path: "{{ item }}"
 
    state: directory
 
    owner: pipreqcheck
 
    group: pipreqcheck
 
    mode: 0750
 
  with_items:
 
    - "/var/lib/pipreqcheck"
 
    - "/var/lib/pipreqcheck/virtualenv"
 
    - "/var/lib/pipreqcheck/virtualenv-py3"
 

	
 
- name: Create Python virtual environment used for installing/running pip-tools
 
  command: "/usr/bin/virtualenv --python '{{ item.python_path }}' --prompt '({{ item.name }})' '{{ item.virtualenv_path }}'"
 
  args:
 
    creates: "{{ item.creates }}"
 
  become: true
 
  become_user: "pipreqcheck"
 
  with_items:
 
    - name: pipreqcheck
 
      virtualenv_path: "/var/lib/pipreqcheck/virtualenv"
 
      python_path: "/usr/bin/python2.7"
 
      creates: "/var/lib/pipreqcheck/virtualenv/bin/python2.7"
 
    - name: pipreqcheck-py3
 
      virtualenv_path: "/var/lib/pipreqcheck/virtualenv-py3"
 
      python_path: "/usr/bin/python3"
 
      creates: "/var/lib/pipreqcheck/virtualenv-py3/bin/python3"
 
      creates: "/var/lib/pipreqcheck/virtualenv/bin/python3"
 

	
 
- name: Create directory for storing pip requirements files
 
  file:
 
    path: "{{ item }}"
 
    state: "directory"
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0750
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades"
 
    - "/etc/pip_check_requirements_upgrades-py3"
 

	
 
- name: Set-up directory for storing pip requirements file for pip-tools virtual environment itself
 
  file:
 
    path: "{{ item }}"
 
    state: "directory"
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0750
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades/pipreqcheck"
 
    - "/etc/pip_check_requirements_upgrades-py3/pipreqcheck"
 

	
 
- name: Deploy .in file for pip requirements in pip-tools virtual environment
 
  template:
 
    src: "pipreqcheck_requirements.in.j2"
 
    dest: "{{ item.path }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0640
 
  with_items:
 
    - path: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in"
 
      requirements: "{{ pip_check_requirements_in }}"
 
    - path: "/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.in"
 
      requirements: "{{ pip_check_requirements_py3_in }}"
 

	
 
- name: Deploy requirements file for pipreqcheck virtual environment
 
  template:
 
    src: "pipreqcheck_requirements.txt.j2"
 
    dest: "{{ item.file }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0640
 
  with_items:
 
    - file: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
      requirements: "{{ pip_check_requirements }}"
 
    - file: "/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.txt"
 
      requirements: "{{ pip_check_requirements_py3 }}"
 

	
 
- name: Install requirements in the pipreqcheck virtual environment
 
  pip:
 
    requirements: "{{ item.requirements }}"
 
    virtualenv: "{{ item.virtualenv }}"
 
  become: true
 
  become_user: pipreqcheck
 
  with_items:
 
    - virtualenv: "~pipreqcheck/virtualenv"
 
      requirements: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
    - virtualenv: "~pipreqcheck/virtualenv-py3"
 
      requirements: "/etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.txt"
 

	
 
- name: Synchronise pip-tools virtual environment via deployed requirements file (Python 2)
 
- name: Synchronise pip-tools virtual environment via deployed requirements file
 
  shell: "source ~pipreqcheck/virtualenv/bin/activate && pip-sync /etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
  args:
 
    executable: /bin/bash
 
  become: true
 
  become_user: "pipreqcheck"
 
  register: pipreqcheck_pip_sync
 
  changed_when: "pipreqcheck_pip_sync.stdout != 'Everything up-to-date'"
 

	
 
- name: Synchronise pip-tools virtual environment via deployed requirements file (Python 3)
 
  shell: "source ~pipreqcheck/virtualenv-py3/bin/activate && pip-sync /etc/pip_check_requirements_upgrades-py3/pipreqcheck/requirements.txt"
 
  args:
 
    executable: /bin/bash
 
  become: true
 
  become_user: "pipreqcheck"
 
  register: pipreqcheck_pip_sync
 
  changed_when: "pipreqcheck_pip_sync.stdout != 'Everything up-to-date'"
 

	
 
- name: Deploy script for checking available upgrades
 
  copy:
 
    src: "pip_check_requirements_upgrades.sh"
 
    dest: "/usr/local/bin/pip_check_requirements_upgrades.sh"
 
    owner: root
 
    group: root
 
    mode: 0755
 

	
 
- name: Deploy crontab entry for checking pip requirements
 
  copy:
 
    src: "cron_check_pip_requirements"
 
    dest: "/etc/cron.d/check_pip_requirements"
 
    owner: root
 
    group: root
 
    mode: 0644
 

	
 
- name: Deploy crontab entry for checking pip requirements
 
  copy:
 
    src: "cron_check_pip_requirements-py3"
 
    dest: "/etc/cron.d/check_pip_requirements-py3"
 
    owner: root
 
    group: root
 
    mode: 0644
 

	
 
- name: Install NTP packages
 
  apt:
 
    name:
 
      - ntp
 
      - ntpdate
 
    state: present
 
  when: ntp_servers | length > 0
 

	
 
- name: Deploy NTP configuration
 
  template:
 
    src: "ntp.conf.j2"
 
    dest: "/etc/ntp.conf"
0 comments (0 inline, 0 general)