Vendor Galaxy Roles and Collections
This commit is contained in:
parent
c1e1897cda
commit
2aed20393f
3553 changed files with 387444 additions and 2 deletions
19
ansible_collections/debops/debops/roles/ansible/COPYRIGHT
Normal file
19
ansible_collections/debops/debops/roles/ansible/COPYRIGHT
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
debops.ansible - Install Ansible on a Debian/Ubuntu host using Ansible
|
||||
|
||||
Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _ansible__ref_defaults:
|
||||
|
||||
# debops.ansible default variables
|
||||
# ================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# Installation, APT packages [[[
|
||||
# ------------------------------
|
||||
|
||||
# .. envvar:: ansible__deploy_type [[[
|
||||
#
|
||||
# Select how Ansible should be installed by the role:
|
||||
#
|
||||
# - ``system``: install Ansible using current OS packages, possibly from the
|
||||
# backports repository.
|
||||
#
|
||||
# - ``upstream``: install Ansible from the upstream APT repository on
|
||||
# Launchpad (PPA, usable on Debian as well).
|
||||
#
|
||||
# - ``bootstrap``: install APT packages required for Ansible and build a local
|
||||
# ``.deb`` package using the upstream GitHub repository.
|
||||
#
|
||||
ansible__deploy_type: '{{ "upstream"
|
||||
if (ansible_distribution_release in
|
||||
["trusty", "xenial"])
|
||||
else "system" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__upstream_apt_key [[[
|
||||
#
|
||||
# The OpenPGP key of the Ansible upstream APT repository.
|
||||
ansible__upstream_apt_key: '6125 E2A8 C77F 2818 FB7B D15B 93C4 A3FD 7BB9 C367'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__upstream_apt_repository [[[
|
||||
#
|
||||
# The APT repository URI of the upstream Ansible repository.
|
||||
ansible__upstream_apt_repository: 'deb http://ppa.launchpad.net/ansible/ansible/ubuntu xenial main'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__base_packages [[[
|
||||
#
|
||||
# List of APT packages to install for Ansible support.
|
||||
ansible__base_packages:
|
||||
- '{{ "ansible"
|
||||
if (ansible__deploy_type in ["system", "upstream"])
|
||||
else [] }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__packages [[[
|
||||
#
|
||||
# List of additional APT packages to install with Ansible.
|
||||
ansible__packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__bootstrap_version [[[
|
||||
#
|
||||
# Specify the :command:`git` repository branch, tag or commit id which should
|
||||
# be used by the :command:`bootstrap-ansible` script to build the Ansible
|
||||
# ``.deb`` package.
|
||||
ansible__bootstrap_version: 'devel'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Configuration for other Ansible roles [[[
|
||||
# -----------------------------------------
|
||||
|
||||
# .. envvar:: ansible__apt_preferences__dependent_list [[[
|
||||
#
|
||||
# Configuration for the :ref:`debops.apt_preferences` Ansible role.
|
||||
ansible__apt_preferences__dependent_list:
|
||||
|
||||
- package: 'ansible'
|
||||
backports: [ "stretch", "buster" ]
|
||||
reason: 'Compatibility with upstream release'
|
||||
by_role: 'debops_ansible'
|
||||
state: '{{ "absent"
|
||||
if (ansible__deploy_type == "upstream")
|
||||
else "present" }}'
|
||||
|
||||
- package: 'ansible'
|
||||
pin: 'release o=LP-PPA-ansible-ansible'
|
||||
priority: '600'
|
||||
by_role: 'debops_ansible'
|
||||
filename: 'debops_ansible_upstream.pref'
|
||||
reason: 'Recent version from upstream PPA'
|
||||
state: '{{ "present"
|
||||
if (ansible__deploy_type == "upstream")
|
||||
else "absent" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: ansible__keyring__dependent_apt_keys [[[
|
||||
#
|
||||
# Configuration for the :ref:`debops.keyring` Ansible role.
|
||||
ansible__keyring__dependent_apt_keys:
|
||||
|
||||
- id: '{{ ansible__upstream_apt_key }}'
|
||||
repo: '{{ ansible__upstream_apt_repository }}'
|
||||
state: '{{ "present" if (ansible__deploy_type == "upstream") else "absent" }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
160
ansible_collections/debops/debops/roles/ansible/files/script/bootstrap-ansible
Executable file
160
ansible_collections/debops/debops/roles/ansible/files/script/bootstrap-ansible
Executable file
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# bootstrap-ansible: download and build Ansible on a Debian/Ubuntu host
|
||||
|
||||
# Copyright (C) 2014-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2014-2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
|
||||
# Usage: ./bootstrap-ansible [branch] [build_directory]
|
||||
|
||||
set -o nounset -o pipefail -o errexit
|
||||
|
||||
|
||||
DEBIAN_VERSION="$(sed 's/\..*//' /etc/debian_version)"
|
||||
readonly DEBIAN_VERSION
|
||||
|
||||
ansible_branch="${1:-devel}"
|
||||
build_dir="${2:-}"
|
||||
|
||||
if [ -z "${build_dir}" ] ; then
|
||||
build_dir="$(mktemp -d)"
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -rf ${build_dir}" EXIT
|
||||
fi
|
||||
|
||||
install_ansible_requirements () {
|
||||
|
||||
local -a apt_packages
|
||||
|
||||
apt_packages=( git devscripts cdbs debhelper dpkg-dev fakeroot sshpass \
|
||||
asciidoc xmlto build-essential lsb-release dh-python )
|
||||
|
||||
apt_packages+=(
|
||||
python-crypto \
|
||||
python-cryptography \
|
||||
python-dnspython \
|
||||
python-httplib2 \
|
||||
python-jinja2 \
|
||||
python-ldap \
|
||||
python-nose \
|
||||
python-paramiko \
|
||||
python-passlib \
|
||||
python-setuptools \
|
||||
python-sphinx \
|
||||
python-yaml
|
||||
)
|
||||
|
||||
if [ "${DEBIAN_VERSION}" -gt 8 ] ; then
|
||||
apt_packages+=( python-packaging )
|
||||
fi
|
||||
|
||||
sudo apt-get --no-install-recommends -y install "${apt_packages[@]}"
|
||||
}
|
||||
|
||||
build_ansible_deb () {
|
||||
|
||||
# Build Debian package
|
||||
if [ -n "$(grep 'local_deb' Makefile || true)" ] ; then
|
||||
LANG=C make local_deb > /tmp/ansible-deb-build.log \
|
||||
|| tail -n 50 /tmp/ansible-deb-build.log
|
||||
else
|
||||
LANG=C make deb > /tmp/ansible-deb-build.log \
|
||||
|| tail -n 50 /tmp/ansible-deb-build.log
|
||||
fi
|
||||
|
||||
# Check if .deb package with new method is present
|
||||
if [ -n "$(find deb-build/unstable/ -name "ansible_*_all.deb" 2>/dev/null)" ]; then
|
||||
|
||||
sudo dpkg -i deb-build/unstable/ansible_*_all.deb
|
||||
|
||||
# Otherwise, look for package generated with old method
|
||||
elif [ -n "$(find .. -name "ansible_*_all.deb" 2>/dev/null)" ]; then
|
||||
|
||||
sudo dpkg -i ../ansible_*_all.deb
|
||||
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
bootstrap_ansible_deb () {
|
||||
|
||||
local ansible_branch
|
||||
local build_dir
|
||||
local ansible_git_repo
|
||||
local ansible_source_dir
|
||||
|
||||
ansible_branch="${1:-devel}"
|
||||
build_dir="${2:-$(mktemp -d)}"
|
||||
ansible_git_repo="${3:-https://github.com/ansible/ansible}"
|
||||
ansible_source_dir="ansible"
|
||||
|
||||
if [ ! -d "${build_dir}" ] ; then
|
||||
mkdir -p "${build_dir}"
|
||||
fi
|
||||
|
||||
cd "${build_dir}" || exit 1
|
||||
|
||||
if [ -d "${ansible_source_dir}" ] ; then
|
||||
|
||||
cd "${ansible_source_dir}" || exit 1
|
||||
|
||||
local old_git_checkout
|
||||
local current_branch_name
|
||||
local current_branch_name
|
||||
local current_branch_name
|
||||
|
||||
old_git_checkout="$(git rev-parse HEAD)"
|
||||
current_branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
|
||||
current_branch_name="(unnamed branch)" # detached HEAD
|
||||
current_branch_name=${current_branch_name##refs/heads/}
|
||||
|
||||
if [ "${current_branch_name}" != "${ansible_branch}" ] ; then
|
||||
git checkout "${ansible_branch}"
|
||||
fi
|
||||
|
||||
git pull --quiet
|
||||
git submodule update
|
||||
|
||||
local current_git_checkout
|
||||
|
||||
current_git_checkout="$(git rev-parse HEAD)"
|
||||
|
||||
if [ "${old_git_checkout}" != "${current_git_checkout}" ] ; then
|
||||
build_ansible_deb
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
install_ansible_requirements
|
||||
git clone --branch "${ansible_branch}" --recursive "${ansible_git_repo}" "${ansible_source_dir}"
|
||||
cd "${ansible_source_dir}" || exit 1
|
||||
build_ansible_deb
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
bootstrap_ansible_deb "${ansible_branch}" "${build_dir}"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'Install Ansible on Debian/Ubuntu host using Ansible'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.4.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- ansible
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", (ansible__base_packages
|
||||
+ ansible__packages)) }}'
|
||||
state: 'present'
|
||||
register: ansible__register_packages
|
||||
until: ansible__register_packages is succeeded
|
||||
|
||||
- name: Bootstrap Ansible from source
|
||||
ansible.builtin.script: 'script/bootstrap-ansible "{{ ansible__bootstrap_version }}"'
|
||||
when: (ansible__deploy_type == 'bootstrap' and
|
||||
(ansible_local is undefined or
|
||||
(ansible_local.ansible is undefined or
|
||||
not (ansible_local.ansible.installed | d()) | bool or
|
||||
(ansible_local.ansible.deploy_type | d(ansible__deploy_type) != 'bootstrap'))))
|
||||
|
||||
- name: Make sure that Ansible local fact directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Save Ansible local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/ansible.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/ansible.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
notify: [ 'Refresh host facts' ]
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Re-read local facts if they have been modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import loads, dumps
|
||||
from sys import exit
|
||||
import os
|
||||
|
||||
|
||||
def cmd_exists(cmd):
|
||||
return any(
|
||||
os.access(os.path.join(path, cmd), os.X_OK)
|
||||
for path in os.environ["PATH"].split(os.pathsep)
|
||||
)
|
||||
|
||||
|
||||
output = loads('''{{ {"installed": False,
|
||||
"deploy_type": ansible__deploy_type}
|
||||
| to_nice_json }}''')
|
||||
|
||||
output['installed'] = cmd_exists('ansible-playbook')
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
debops.ansible_plugins - Custom Ansible plugins used by DebOps
|
||||
|
||||
Copyright (C) 2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2017 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This repository is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,193 @@
|
|||
# Copyright (C) 2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# This file is part of DebOps.
|
||||
#
|
||||
# DebOps is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# DebOps is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with DebOps. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from operator import itemgetter
|
||||
|
||||
try:
|
||||
unicode = unicode
|
||||
except NameError:
|
||||
# py3
|
||||
unicode = str
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
def _mangle_recipients(name, *args):
|
||||
"""Modify the recipient address if it's the same as alias
|
||||
to prevent mail forwarding loops
|
||||
Ref: https://serverfault.com/questions/471604/
|
||||
"""
|
||||
|
||||
input_args = []
|
||||
|
||||
# Flatten the input list
|
||||
for sublist in list(args):
|
||||
for item in sublist:
|
||||
input_args.append(item)
|
||||
|
||||
if name in input_args:
|
||||
return [w.replace(name, '\\' + name) for w in input_args]
|
||||
else:
|
||||
return input_args
|
||||
|
||||
|
||||
def _update_recipients(current_data, new_data, *args, **kwargs):
|
||||
"""Replace the current list of recipients with a new one"""
|
||||
|
||||
for selector in args:
|
||||
if selector in new_data:
|
||||
new_recipients = ([new_data.get(selector)]
|
||||
if isinstance(new_data.get(selector),
|
||||
(str, unicode))
|
||||
else new_data.get(selector))
|
||||
current_data.update({'recipients':
|
||||
_mangle_recipients(current_data.get('name'),
|
||||
new_recipients)})
|
||||
|
||||
|
||||
def _add_recipients(current_data, new_data, *args, **kwargs):
|
||||
"""Add mail recipients to an existing list of recipients"""
|
||||
|
||||
for selector in args:
|
||||
if selector in new_data:
|
||||
current_recipients = current_data.get('recipients', [])
|
||||
current_recipients.extend([new_data.get(selector)]
|
||||
if isinstance(new_data.get(selector),
|
||||
(str, unicode))
|
||||
else new_data.get(selector))
|
||||
current_data.update({'recipients':
|
||||
_mangle_recipients(current_data.get('name'),
|
||||
current_recipients)})
|
||||
|
||||
|
||||
def _del_recipients(current_data, new_data, *args, **kwargs):
|
||||
"""Remove mail recipients from an existing list"""
|
||||
|
||||
for selector in args:
|
||||
if selector in new_data:
|
||||
deleted_recipients = ([new_data.get(selector)]
|
||||
if isinstance(new_data.get(selector),
|
||||
(str, unicode))
|
||||
else new_data.get(selector))
|
||||
current_recipients = current_data.get('recipients', [])
|
||||
new_recipients = [x for x in current_recipients
|
||||
if x not in deleted_recipients]
|
||||
current_data.update({'recipients': new_recipients})
|
||||
|
||||
|
||||
def etc_aliases_parse_recipients(*args, **kwargs):
|
||||
"""Return a parsed list of mail aliases and recipients"""
|
||||
|
||||
input_args = []
|
||||
parsed_aliases = {}
|
||||
|
||||
# Flatten the input list
|
||||
for sublist in list(args):
|
||||
for item in sublist:
|
||||
input_args.append(item)
|
||||
|
||||
for element in input_args:
|
||||
if isinstance(element, dict):
|
||||
if (any(x in element for x in ['name', 'alias']) and
|
||||
element.get('state', 'present') != 'ignore'):
|
||||
|
||||
alias_name = element.get('alias', element.get('name'))
|
||||
current_alias = (parsed_aliases[alias_name].copy()
|
||||
if alias_name in parsed_aliases
|
||||
else {})
|
||||
|
||||
current_alias.update({
|
||||
'name': alias_name, # in case of a new entry
|
||||
'state': element.get('state',
|
||||
current_alias.get('state',
|
||||
'present')),
|
||||
'weight': int(element.get('weight',
|
||||
current_alias.get('weight', 0))),
|
||||
'section': element.get('section',
|
||||
current_alias.get('section',
|
||||
'unknown'))
|
||||
})
|
||||
|
||||
_update_recipients(current_alias, element, 'dest', 'to')
|
||||
|
||||
_add_recipients(current_alias, element,
|
||||
'add_dest', 'add_to', 'cc', 'bcc')
|
||||
|
||||
_del_recipients(current_alias, element,
|
||||
'del_dest', 'del_to')
|
||||
|
||||
if 'real_name' in element or 'real_alias' in element:
|
||||
current_alias['real_name'] = (
|
||||
element.get('real_name',
|
||||
element.get('real_alias')))
|
||||
|
||||
if 'comment' in element:
|
||||
current_alias['comment'] = element.get('comment')
|
||||
|
||||
if not current_alias.get('recipients', ''):
|
||||
current_alias['state'] = 'comment'
|
||||
|
||||
parsed_aliases.update({alias_name: current_alias})
|
||||
|
||||
# These parameters are special and should not be interpreted
|
||||
# directly as mail aliases.
|
||||
elif not all(x in ['name', 'alias', 'state', 'comment',
|
||||
'section', 'weight', 'dest', 'to',
|
||||
'add_dest', 'add_to', 'cc', 'bcc',
|
||||
'del_dest', 'del_to']
|
||||
for x in element):
|
||||
for key, value in element.items():
|
||||
current_alias = parsed_aliases.get(key, {}).copy()
|
||||
current_alias.update({
|
||||
'name': key,
|
||||
'recipients': (_mangle_recipients(
|
||||
current_alias.get('name'), [value]
|
||||
if isinstance(value, (str, unicode))
|
||||
else value)),
|
||||
'state': 'present',
|
||||
'weight': int(element.get('weight',
|
||||
current_alias.get('weight', 0))),
|
||||
'section': current_alias.get('section', 'unknown')
|
||||
})
|
||||
|
||||
current_alias.update({
|
||||
'recipients': (_mangle_recipients(
|
||||
current_alias.get('name'),
|
||||
([value]
|
||||
if isinstance(value, (str, unicode))
|
||||
else value)))
|
||||
})
|
||||
|
||||
if not current_alias.get('recipients', ''):
|
||||
current_alias['state'] = 'comment'
|
||||
|
||||
parsed_aliases[key] = current_alias
|
||||
|
||||
# Expand the dictionary of aliases into a list,
|
||||
# and return sorted by weight.
|
||||
return sorted(parsed_aliases.values(), key=itemgetter('weight', 'name'))
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
"""Register custom filter plugins in Ansible"""
|
||||
|
||||
def filters(self):
|
||||
return {'etc_aliases_parse_recipients': etc_aliases_parse_recipients}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (C) 2015 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from ansible import errors
|
||||
|
||||
try:
|
||||
import fnmatch
|
||||
except Exception as e:
|
||||
raise errors.AnsibleFilterError('fnmatch python library not found')
|
||||
|
||||
|
||||
def globmatch_filter(value, pattern):
|
||||
''' Return string or list of items matching given glob pattern(s). '''
|
||||
|
||||
if not isinstance(pattern, (list, tuple)):
|
||||
pattern = [pattern]
|
||||
|
||||
if isinstance(value, (list, tuple)):
|
||||
_ret = []
|
||||
|
||||
for element in pattern:
|
||||
for entry in value:
|
||||
if fnmatch.fnmatch(str(entry), str(element)):
|
||||
if entry not in _ret:
|
||||
_ret.append(entry)
|
||||
|
||||
if _ret:
|
||||
return _ret
|
||||
else:
|
||||
return list()
|
||||
|
||||
else:
|
||||
|
||||
for element in pattern:
|
||||
if fnmatch.fnmatch(str(value), str(element)):
|
||||
return value
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
''' Return string or list of items matching given glob pattern(s). '''
|
||||
def filters(self):
|
||||
return {
|
||||
'globmatch': globmatch_filter
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
# (c) 2014 Tim Raasveld <info@webtrein.nl>
|
||||
# https://github.com/timraasveld/ansible-string-split-filter/
|
||||
# (c) 2014 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# https://debops.org/
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
|
||||
# License: CC0 1.0 Universal
|
||||
#
|
||||
# Statement of Purpose
|
||||
#
|
||||
# The laws of most jurisdictions throughout the world automatically confer
|
||||
# exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
# subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
# authorship and/or a database (each, a "Work").
|
||||
#
|
||||
# Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
# purpose of contributing to a commons of creative, cultural and scientific
|
||||
# works ("Commons") that the public can reliably and without fear of later
|
||||
# claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
# and redistribute as freely as possible in any form whatsoever and for any
|
||||
# purposes, including without limitation commercial purposes. These owners may
|
||||
# contribute to the Commons to promote the ideal of a free culture and the
|
||||
# further production of creative, cultural and scientific works, or to gain
|
||||
# reputation or greater distribution for their Work in part through the use and
|
||||
# efforts of others.
|
||||
#
|
||||
# For these and/or other purposes and motivations, and without any expectation
|
||||
# of additional consideration or compensation, the person associating CC0 with
|
||||
# a Work (the "Affirmer"), to the extent that he or she is an owner of
|
||||
# Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to
|
||||
# the Work and publicly distribute the Work under its terms, with knowledge of
|
||||
# his or her Copyright and Related Rights in the Work and the meaning and
|
||||
# intended legal effect of CC0 on those rights.
|
||||
#
|
||||
# 1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
# protected by copyright and related or neighboring rights ("Copyright and
|
||||
# Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
# to, the following:
|
||||
#
|
||||
# i. the right to reproduce, adapt, distribute, perform, display,
|
||||
# communicate, and translate a Work;
|
||||
#
|
||||
# ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
#
|
||||
# iii. publicity and privacy rights pertaining to a person's image or
|
||||
# likeness depicted in a Work;
|
||||
#
|
||||
# iv. rights protecting against unfair competition in regards to a Work,
|
||||
# subject to the limitations in paragraph 4(a), below;
|
||||
#
|
||||
# v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
# in a Work;
|
||||
#
|
||||
# vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
# European Parliament and of the Council of 11 March 1996 on the legal
|
||||
# protection of databases, and under any national implementation thereof,
|
||||
# including any amended or successor version of such directive); and
|
||||
#
|
||||
# vii. other similar, equivalent or corresponding rights throughout the world
|
||||
# based on applicable law or treaty, and any national implementations
|
||||
# thereof.
|
||||
#
|
||||
# 2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
# applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
# unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
# and Related Rights and associated claims and causes of action, whether now
|
||||
# known or unknown (including existing as well as future claims and causes of
|
||||
# action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
# duration provided by applicable law or treaty (including future time
|
||||
# extensions), (iii) in any current or future medium and for any number of
|
||||
# copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
# commercial, advertising or promotional purposes (the "Waiver"). Affirmer
|
||||
# makes the Waiver for the benefit of each member of the public at large and to
|
||||
# the detriment of Affirmer's heirs and successors, fully intending that such
|
||||
# Waiver shall not be subject to revocation, rescission, cancellation,
|
||||
# termination, or any other legal or equitable action to disrupt the quiet
|
||||
# enjoyment of the Work by the public as contemplated by Affirmer's express
|
||||
# Statement of Purpose.
|
||||
#
|
||||
# 3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
# judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
# shall be preserved to the maximum extent permitted taking into account
|
||||
# Affirmer's express Statement of Purpose. In addition, to the extent the
|
||||
# Waiver is so judged Affirmer hereby grants to each affected person
|
||||
# a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
# irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
# Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
# maximum duration provided by applicable law or treaty (including future time
|
||||
# extensions), (iii) in any current or future medium and for any number of
|
||||
# copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
# commercial, advertising or promotional purposes (the "License"). The License
|
||||
# shall be deemed effective as of the date CC0 was applied by Affirmer to the
|
||||
# Work. Should any part of the License for any reason be judged legally invalid
|
||||
# or ineffective under applicable law, such partial invalidity or
|
||||
# ineffectiveness shall not invalidate the remainder of the License, and in
|
||||
# such case Affirmer hereby affirms that he or she will not (i) exercise any of
|
||||
# his or her remaining Copyright and Related Rights in the Work or (ii) assert
|
||||
# any associated claims and causes of action with respect to the Work, in
|
||||
# either case contrary to Affirmer's express Statement of Purpose.
|
||||
#
|
||||
# 4. Limitations and Disclaimers.
|
||||
#
|
||||
# a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
# surrendered, licensed or otherwise affected by this document.
|
||||
#
|
||||
# b. Affirmer offers the Work as-is and makes no representations or
|
||||
# warranties of any kind concerning the Work, express, implied, statutory or
|
||||
# otherwise, including without limitation warranties of title,
|
||||
# merchantability, fitness for a particular purpose, non infringement, or the
|
||||
# absence of latent or other defects, accuracy, or the present or absence of
|
||||
# errors, whether or not discoverable, all to the greatest extent permissible
|
||||
# under applicable law.
|
||||
#
|
||||
# c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
# that may apply to the Work or any use thereof, including without limitation
|
||||
# any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
# disclaims responsibility for obtaining any necessary consents, permissions
|
||||
# or other rights required for any use of the Work.
|
||||
#
|
||||
# d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
# party to this document and has no duty or obligation with respect to this
|
||||
# CC0 or use of the Work.
|
||||
#
|
||||
# For more information, please see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def split_string(string, separator=None, maxsplit=-1):
|
||||
try:
|
||||
return string.split(separator, maxsplit)
|
||||
except Exception:
|
||||
return list(string)
|
||||
|
||||
|
||||
def split_regex(string, seperator_pattern):
|
||||
try:
|
||||
return re.split(seperator_pattern, string)
|
||||
except Exception:
|
||||
return list(string)
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
''' A filter to split a string into a list. '''
|
||||
def filters(self):
|
||||
return {
|
||||
'split': split_string,
|
||||
'split_regex': split_regex,
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# Copyright (C) 2017, Matt Martz <matt@sivel.net>
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import functools
|
||||
|
||||
from ansible.plugins.inventory.toml import HAS_TOML, toml_dumps
|
||||
try:
|
||||
from ansible.plugins.inventory.toml import toml
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.common._collections_compat import MutableMapping
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
|
||||
def _check_toml(func):
|
||||
@functools.wraps(func)
|
||||
def inner(o):
|
||||
if not HAS_TOML:
|
||||
raise AnsibleFilterError('The %s filter plugin requires '
|
||||
'the python "toml" library' % func.__name__)
|
||||
return func(o)
|
||||
return inner
|
||||
|
||||
|
||||
@_check_toml
|
||||
def from_toml(o):
|
||||
if not isinstance(o, string_types):
|
||||
raise AnsibleFilterError('from_toml requires a string, got %s' % type(o))
|
||||
return toml.loads(to_text(o, errors='surrogate_or_strict'))
|
||||
|
||||
|
||||
@_check_toml
|
||||
def to_toml(o):
|
||||
if not isinstance(o, MutableMapping):
|
||||
raise AnsibleFilterError('to_toml requires a dict, got %s' % type(o))
|
||||
return to_text(toml_dumps(o), errors='surrogate_or_strict')
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
'to_toml': to_toml,
|
||||
'from_toml': from_toml
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# cran.py: install or remove R packages
|
||||
# Homepage: https://github.com/yutannihilation/ansible-module-cran
|
||||
|
||||
# Copyright (C) 2016 Hiroaki Yutani <yutani.ini@gmail.com>
|
||||
# Copyright (C) 2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: cran
|
||||
short_description: Install R packages.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of an R package.
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- The state of module
|
||||
required: false
|
||||
choices: ['present', 'absent']
|
||||
default: present
|
||||
repo:
|
||||
description:
|
||||
- The repository
|
||||
required: false
|
||||
default: "https://cran.rstudio.com/"
|
||||
'''
|
||||
|
||||
RSCRIPT = '/usr/bin/Rscript'
|
||||
|
||||
|
||||
def get_installed_version(module):
|
||||
cmnd = [RSCRIPT, '--slave', '--no-save', '--no-restore-history', '-e',
|
||||
'p <- installed.packages(); cat(p[p[,1] == "{name:}",'
|
||||
'3])'.format(name=module.params['name'])]
|
||||
(rc, stdout, stderr) = module.run_command(cmnd, check_rc=False)
|
||||
return stdout.strip() if rc == 0 else None
|
||||
|
||||
|
||||
def install(module):
|
||||
cmnd = [RSCRIPT, '--slave', '--no-save', '--no-restore-history', '-e',
|
||||
'install.packages(pkgs="{name:}",repos="{repos:}")'
|
||||
''.format(name=module.params['name'],
|
||||
repos=module.params['repo'])]
|
||||
(rc, stdout, stderr) = module.run_command(cmnd, check_rc=True)
|
||||
return stderr
|
||||
|
||||
|
||||
def uninstall(module):
|
||||
cmnd = [RSCRIPT, '--slave', '--no-save', '--no-restore-history', '-e',
|
||||
'remove.packages(pkgs="{name:}")'
|
||||
''.format(name=module.params['name'])]
|
||||
(rc, stdout, stderr) = module.run_command(cmnd, check_rc=True)
|
||||
return stderr
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
name=dict(required=True),
|
||||
repo=dict(default='https://cran.rstudio.com/')
|
||||
)
|
||||
)
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
changed = False
|
||||
version = get_installed_version(module)
|
||||
|
||||
if state == 'present' and not version:
|
||||
stderr = install(module)
|
||||
version = get_installed_version(module)
|
||||
if not version:
|
||||
module.fail_json(
|
||||
msg='Failed to install {name:}: {err:}'.format(
|
||||
name=name, err=stderr, version=version))
|
||||
changed = True
|
||||
|
||||
elif state == 'absent' and version:
|
||||
stderr = uninstall(module)
|
||||
version = get_installed_version(module)
|
||||
if version:
|
||||
module.fail_json(
|
||||
msg='Failed to install {name:}: {err:}'.format(
|
||||
name=name, err=stderr))
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed, name=name, version=version)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
# Copyright (c) 2017-2018, Yann Amar <quidame@poivron.org>
|
||||
# Copyright (c) 2019, Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (c) 2019, DebOps https://debops.org/
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# Source: https://github.com/quidame/ansible-module-dpkg_divert
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os.path
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: dpkg_divert
|
||||
short_description: Override a package's version of a file
|
||||
description:
|
||||
- A diversion is for C(dpkg) the knowledge that only a given I(package)
|
||||
is allowed to install a file at a given I(path). Other packages shipping
|
||||
their own version of this file will be forced to I(divert) it, i.e. to
|
||||
install it at another location. It allows one to keep changes in a file
|
||||
provided by a debian package by preventing its overwrite at package
|
||||
upgrade.
|
||||
- This module manages diversions of debian packages files using the
|
||||
C(dpkg-divert)(1) commandline tool. It can either create or remove a
|
||||
diversion for a given file, but also update an existing diversion to
|
||||
modify its holder and/or its divert path.
|
||||
- It's a feature of this module to mimic C(dpkg-divert)'s behaviour
|
||||
regarding the renaming of files when removing as well as adding a
|
||||
diversion; existing files are never overwritten.
|
||||
version_added: "2.4"
|
||||
author: "quidame@poivron.org"
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- The original and absolute path of the file to be diverted or
|
||||
undiverted. This path is unique, i.e. it is not possible to get
|
||||
two diversions for the same I(path).
|
||||
required: true
|
||||
type: 'path'
|
||||
aliases: [ 'name' ]
|
||||
state:
|
||||
description:
|
||||
- When I(state=absent), remove the diversion of the specified
|
||||
I(path); when I(state=present), create the diversion if it does
|
||||
not exist, or update its I(package) holder or I(divert) path,
|
||||
if any, and if I(force) is C(True).
|
||||
- Unless I(force) is C(True), the removal of I(path)'s diversion
|
||||
only happens if the diversion matches the I(divert) and
|
||||
I(package) values, if any.
|
||||
type: 'string'
|
||||
default: 'present'
|
||||
choices: [ 'absent', 'present' ]
|
||||
package:
|
||||
description:
|
||||
- The name of the package whose copy of file is not diverted, also
|
||||
known as the diversion holder or the package the diversion
|
||||
belongs to.
|
||||
- The actual package does not have to be installed or even to exist
|
||||
for its name to be valid. If not specified, the diversion is held
|
||||
by 'LOCAL', which is reserved for local diversions.
|
||||
- Removing or updating a diversion fails if the diversion exists
|
||||
and belongs to another package, unless I(force) is C(True).
|
||||
divert:
|
||||
description:
|
||||
- The location where the versions of file will be diverted.
|
||||
- The default suffix is C(.distrib) for diversions defined by a
|
||||
package and C(.dpkg-divert) for 'LOCAL' diversions.
|
||||
type: 'path'
|
||||
rename:
|
||||
description:
|
||||
- Actually move the file aside (or back).
|
||||
- Renaming is skipped (but module doesn't fail) in case the
|
||||
destination file already exists. This is a C(dpkg-divert)
|
||||
feature, and its purpose is to never overwrite a file. It also
|
||||
makes the command itself idempotent, and the module's I(force)
|
||||
parameter has no effect on this behaviour.
|
||||
- Also, I(rename) is ignored if the diversion entry is unchanged
|
||||
in the diversion database (adding an already existing diversion
|
||||
or removing a non-existing one).
|
||||
type: 'bool'
|
||||
default: true
|
||||
delete:
|
||||
description:
|
||||
- When I(yes), delete the file in place of the original before
|
||||
reverting. This only applies with I(state=absent) to avoid
|
||||
C(dpkg-divert) command complaining about existing file in place
|
||||
of the diverted one.
|
||||
type: 'bool'
|
||||
default: false
|
||||
force:
|
||||
description:
|
||||
- Force to divert file when diversion already exists and is hold
|
||||
by another I(package) or points to another I(divert). There is
|
||||
no need to use it for I(remove) action if I(divert) or I(package)
|
||||
are not used.
|
||||
- This doesn't override the rename's lock feature, i.e. it doesn't
|
||||
help to force I(rename), but only to force the diversion for
|
||||
dpkg.
|
||||
type: 'bool'
|
||||
default: false
|
||||
requirements: [ dpkg-divert, env ]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Divert /etc/screenrc to /etc/screenrc.dpkg-divert and rename the file
|
||||
- name: Create local diversion
|
||||
dpkg_divert: path=/etc/screenrc
|
||||
|
||||
# Divert /etc/screenrc to /etc/screenrc.distrib for package 'branding' and
|
||||
# rename the file
|
||||
- name: Create diversion for APT package
|
||||
dpkg_divert:
|
||||
name: /etc/screenrc
|
||||
package: branding
|
||||
|
||||
- name: Delete the file in place of the original and remove the diversion
|
||||
dpkg_divert:
|
||||
name: /etc/screenrc
|
||||
state: absent
|
||||
delete: yes
|
||||
|
||||
- name: remove the screenrc diversion only if belonging to 'branding'
|
||||
dpkg_divert:
|
||||
name: /etc/screenrc
|
||||
package: branding
|
||||
state: absent
|
||||
|
||||
# Divert screenrc to screenrc.dpkg-divert, but don't rename the file
|
||||
- name: Divert with custom rename
|
||||
dpkg_divert:
|
||||
path: /etc/screenrc
|
||||
divert: /etc/screenrc.dpkg-divert
|
||||
rename: no
|
||||
|
||||
# Divert and rename screenrc to screenrc.dpkg-divert, even if diversion is
|
||||
# already set
|
||||
- name: Divert with custom rename
|
||||
dpkg_divert:
|
||||
path: /etc/screenrc
|
||||
divert: /etc/screenrc.dpkg-divert
|
||||
rename: yes
|
||||
force: yes
|
||||
|
||||
# Remove the screenrc diversion and maybe move the diverted file to its
|
||||
# original place
|
||||
- name: Remove diversion and rename file
|
||||
dpkg_divert:
|
||||
path: /etc/screenrc
|
||||
state: absent
|
||||
rename: yes
|
||||
'''
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Mimic the behaviour of the dpkg-divert(1) command: '--add' is implicit
|
||||
# when not using '--remove'; '--rename' takes care to never overwrite
|
||||
# existing files; and options are intended to not conflict between them.
|
||||
|
||||
# 'force' is an option of the module, not of the command, and implies to
|
||||
# run the command twice. Its purpose is to allow one to re-divert a file
|
||||
# with another target path or to 'give' it to another package, in one task.
|
||||
# This is very easy because one of the values is unique in the diversion
|
||||
# database, and dpkg-divert itself is idempotent (does nothing when nothing
|
||||
# needs doing).
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
path=dict(required=True, type='path', aliases=['name']),
|
||||
state=dict(required=False, type='str', default='present',
|
||||
choices=['absent', 'present']),
|
||||
package=dict(required=False, type='str', default='LOCAL'),
|
||||
divert=dict(required=False, type='path'),
|
||||
rename=dict(required=False, type='bool', default=True),
|
||||
delete=dict(required=False, type='bool', default=False),
|
||||
force=dict(required=False, type='bool', default=False),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
path = module.params['path']
|
||||
state = module.params['state']
|
||||
package = module.params['package']
|
||||
divert = module.params['divert']
|
||||
rename = module.params['rename']
|
||||
delete = module.params['delete']
|
||||
force = module.params['force']
|
||||
|
||||
DPKG_DIVERT = module.get_bin_path('dpkg-divert', required=True)
|
||||
# We need to parse the command's output, which is localized.
|
||||
# So we have to reset environment variable (LC_ALL).
|
||||
ENVIRONMENT = module.get_bin_path('env', required=True)
|
||||
|
||||
# Start to build the commandline we'll have to run
|
||||
COMMANDLINE = [ENVIRONMENT, 'LC_ALL=C', DPKG_DIVERT, path]
|
||||
|
||||
# Then insert options as requested in the task parameters:
|
||||
if state == 'absent':
|
||||
COMMANDLINE.insert(3, '--remove')
|
||||
elif state == 'present':
|
||||
COMMANDLINE.insert(3, '--add')
|
||||
|
||||
if rename:
|
||||
COMMANDLINE.insert(3, '--rename')
|
||||
|
||||
if divert:
|
||||
COMMANDLINE.insert(3, '--divert')
|
||||
COMMANDLINE.insert(4, divert)
|
||||
else:
|
||||
if package == 'LOCAL':
|
||||
COMMANDLINE.insert(3, '--divert')
|
||||
COMMANDLINE.insert(4, '.'.join([path, 'dpkg-divert']))
|
||||
elif package:
|
||||
COMMANDLINE.insert(3, '--divert')
|
||||
COMMANDLINE.insert(4, '.'.join([path, 'distrib']))
|
||||
|
||||
if package == 'LOCAL':
|
||||
COMMANDLINE.insert(3, '--local')
|
||||
elif package:
|
||||
COMMANDLINE.insert(3, '--package')
|
||||
COMMANDLINE.insert(4, package)
|
||||
|
||||
# dpkg-divert has a useful --test option that we will use in check mode or
|
||||
# when needing to parse output before actually doing anything.
|
||||
TESTCOMMAND = list(COMMANDLINE)
|
||||
TESTCOMMAND.insert(3, '--test')
|
||||
if module.check_mode:
|
||||
COMMANDLINE = list(TESTCOMMAND)
|
||||
|
||||
cmd = ' '.join(COMMANDLINE)
|
||||
|
||||
# `dpkg-divert --listpackage FILE` always returns 0, but not diverted files
|
||||
# provide no output.
|
||||
rc, listpackage, _ = module.run_command(
|
||||
[DPKG_DIVERT, '--listpackage', path])
|
||||
rc, placeholder, _ = module.run_command(TESTCOMMAND)
|
||||
|
||||
# There is probably no need to do more than that. Please read the first
|
||||
# sentence of the next comment for a better understanding of the following
|
||||
# `if` statement:
|
||||
if rc == 0 or not force or not listpackage:
|
||||
|
||||
# If requested, delete the file to make way for the reverted one, but
|
||||
# only of the diversion currently exists.
|
||||
if not module.check_mode:
|
||||
if state == 'absent' and listpackage and delete:
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError as e:
|
||||
# It may already have been removed
|
||||
if e.errno != errno.ENOENT:
|
||||
raise AnsibleModuleError(
|
||||
results={'msg': "unlinking failed: %s "
|
||||
% to_native(e), 'path': path})
|
||||
|
||||
# In the check mode, the 'dpkg-divert' command still tests the
|
||||
# diversion removal for real and returns with an error when a changed
|
||||
# file is in place. In that specific case, we instead simulate a file
|
||||
# deletion and diversion removal ourselves to have the check mode
|
||||
# succeed.
|
||||
if (module.check_mode and state == 'absent' and delete and
|
||||
listpackage and os.path.exists(path)):
|
||||
fake_stdout = ['Deleting', path, 'and', 'removing']
|
||||
if package == 'LOCAL':
|
||||
fake_stdout.append('local')
|
||||
fake_stdout.extend(['diversion', 'of', path, 'to'])
|
||||
if divert:
|
||||
fake_stdout.append(divert)
|
||||
else:
|
||||
if package == 'LOCAL':
|
||||
fake_stdout.append('.'.join([path, 'dpkg-divert']))
|
||||
elif package:
|
||||
fake_stdout.append('.'.join([path, 'distrib']))
|
||||
|
||||
rc, stdout, stderr = [0, ' '.join(fake_stdout), '']
|
||||
else:
|
||||
rc, stdout, stderr = module.run_command(COMMANDLINE, check_rc=True)
|
||||
|
||||
if re.match('^(Leaving|No diversion)', stdout):
|
||||
module.exit_json(changed=False, stdout=stdout,
|
||||
stderr=stderr, cmd=cmd)
|
||||
else:
|
||||
module.exit_json(changed=True, stdout=stdout,
|
||||
stderr=stderr, cmd=cmd)
|
||||
|
||||
# So, here we are: the test failed AND force is true AND a diversion exists
|
||||
# for the file. Anyway, we have to remove it first (then stop here, or add
|
||||
# a new diversion for the same file), and without failure. Cases of failure
|
||||
# with dpkg-divert are:
|
||||
# - The diversion does not belong to the same package (or LOCAL)
|
||||
# - The divert filename is not the same (e.g. path.distrib != path.divert)
|
||||
# So: force removal by stripping '--package' and '--divert' options... and
|
||||
# their arguments. Fortunately, this module accepts only a few parameters,
|
||||
# so we can rebuild a whole command line from scratch at no cost:
|
||||
FORCEREMOVE = [ENVIRONMENT, 'LC_ALL=C', DPKG_DIVERT, '--remove', path]
|
||||
module.check_mode and FORCEREMOVE.insert(3, '--test')
|
||||
rename and FORCEREMOVE.insert(3, '--rename')
|
||||
forcerm = ' '.join(FORCEREMOVE)
|
||||
|
||||
if state == 'absent':
|
||||
rc, stdout, stderr = module.run_command(FORCEREMOVE, check_rc=True)
|
||||
module.exit_json(changed=True, stdout=stdout,
|
||||
stderr=stderr, cmd=forcerm)
|
||||
|
||||
# The situation is that we want to modify the settings (package or divert)
|
||||
# of an existing diversion. dpkg-divert does not handle this, and we have
|
||||
# to remove the diversion and set a new one. First, get state info:
|
||||
rc, truename, _ = module.run_command([DPKG_DIVERT, '--truename', path])
|
||||
rc, rmout, rmerr = module.run_command(FORCEREMOVE, check_rc=True)
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True, cmd=[forcerm, cmd],
|
||||
msg=[rmout,
|
||||
"*** RUNNING IN CHECK MODE ***",
|
||||
"The next step can't be actually performed - "
|
||||
"even dry-run - without error (since the "
|
||||
"previous removal didn't happen) but is "
|
||||
"supposed to achieve the task."])
|
||||
|
||||
old = truename.rstrip()
|
||||
if divert:
|
||||
new = divert
|
||||
else:
|
||||
if package == 'LOCAL':
|
||||
new = '.'.join([path, 'dpkg-divert'])
|
||||
elif package:
|
||||
new = '.'.join([path, 'distrib'])
|
||||
|
||||
# Store state of files as they may change
|
||||
old_exists = os.path.isfile(old)
|
||||
new_exists = os.path.isfile(new)
|
||||
|
||||
# RENAMING NOT REMAINING
|
||||
# The behaviour of this module is to NEVER overwrite a file, i.e. never
|
||||
# change file contents but only file paths and only if not conflicting,
|
||||
# as does dpkg-divert. It means that if there is already a diversion for
|
||||
# a given file and the divert file exists too, the divert file must be
|
||||
# moved from old to new divert paths between the two dpkg-divert commands,
|
||||
# because:
|
||||
#
|
||||
# src = /etc/screenrc (tweaked ; exists)
|
||||
# old = /etc/screentc.distrib (default ; exists)
|
||||
# new = /etc/screenrc.ansible (not existing yet)
|
||||
#
|
||||
# Without extra move:
|
||||
# 1. dpkg-divert --rename --remove src
|
||||
# => dont move old to src because src exists
|
||||
# 2. dpkg-divert --rename --divert new --add src
|
||||
# => move src to new because new doesn't exist
|
||||
# Results:
|
||||
# - old still exists with default contents
|
||||
# - new holds the tweaked contents
|
||||
# - src is missing
|
||||
# => confusing, kind of breakage
|
||||
#
|
||||
# With extra move:
|
||||
# 1. dpkg-divert --rename --remove src
|
||||
# => dont move old to src because src exists
|
||||
# 2. os.path.rename(old, new) [conditional]
|
||||
# => move old to new because new doesn't exist
|
||||
# 3. dpkg-divert --rename --divert new --add src
|
||||
# => dont move src to new because new exists
|
||||
# Results:
|
||||
# - old does not exist anymore
|
||||
# - src is still the same tweaked file
|
||||
# - new exists with default contents
|
||||
# => idempotency for next times, and no breakage
|
||||
#
|
||||
if rename and old_exists and not new_exists:
|
||||
os.rename(old, new)
|
||||
|
||||
rc, stdout, stderr = module.run_command(COMMANDLINE)
|
||||
rc == 0 and module.exit_json(changed=True, stdout=stdout, stderr=stderr,
|
||||
cmd=[forcerm, cmd], msg=[rmout, stdout])
|
||||
|
||||
# Damn! FORCEREMOVE succeeded and COMMANDLINE failed. Try to restore old
|
||||
# state and end up with a 'failed' status anyway.
|
||||
if (rename and (old_exists and not os.path.isfile(old)) and
|
||||
(os.path.isfile(new) and not new_exists)):
|
||||
os.rename(new, old)
|
||||
|
||||
RESTORE = [ENVIRONMENT, 'LC_ALL=C', DPKG_DIVERT, '--divert', old, path]
|
||||
old_pkg = listpackage.rstrip()
|
||||
if old_pkg == "LOCAL":
|
||||
RESTORE.insert(3, '--local')
|
||||
else:
|
||||
RESTORE.insert(3, '--package')
|
||||
RESTORE.insert(4, old_pkg)
|
||||
rename and RESTORE.insert(3, '--rename')
|
||||
|
||||
module.run_command(RESTORE, check_rc=True)
|
||||
module.exit_json(failed=True, changed=True, stdout=stdout,
|
||||
stderr=stderr, cmd=[forcerm, cmd])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,408 @@
|
|||
# Copyright (c) 2016, Peter Sagerson <psagers@ignorare.net>
|
||||
# Copyright (c) 2016, Jiri Tyr <jiri.tyr@gmail.com>
|
||||
# Copyright (c) 2017, Alexander Korinek <noles@a3k.net>
|
||||
# Copyright (c) 2019, Maciej Delmanowski <drybjed@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native, to_bytes
|
||||
|
||||
import traceback
|
||||
import re
|
||||
|
||||
try:
|
||||
import ldap
|
||||
import ldap.sasl
|
||||
|
||||
HAS_LDAP = True
|
||||
except ImportError:
|
||||
HAS_LDAP = False
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ldap_attrs
|
||||
short_description: Add or remove multiple LDAP attribute values.
|
||||
description:
|
||||
- Add or remove multiple LDAP attribute values.
|
||||
notes:
|
||||
- This only deals with attributes on existing entries. To add or remove
|
||||
whole entries, see M(ldap_entry).
|
||||
- The default authentication settings will attempt to use a SASL EXTERNAL
|
||||
bind over a UNIX domain socket. This works well with the default Ubuntu
|
||||
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
|
||||
rule allowing root to modify the server configuration. If you need to use
|
||||
a simple bind to access your server, pass the credentials in I(bind_dn)
|
||||
and I(bind_pw).
|
||||
- For I(state=present) and I(state=absent), all value comparisons are
|
||||
performed on the server for maximum accuracy. For I(state=exact), values
|
||||
have to be compared in Python, which obviously ignores LDAP matching
|
||||
rules. This should work out in most cases, but it is theoretically
|
||||
possible to see spurious changes when target and actual values are
|
||||
semantically identical but lexically distinct.
|
||||
version_added: '2.5'
|
||||
author:
|
||||
- Jiri Tyr (@jtyr)
|
||||
- Alexander Korinek (@noles)
|
||||
requirements:
|
||||
- python-ldap
|
||||
options:
|
||||
bind_dn:
|
||||
required: false
|
||||
default: null
|
||||
description:
|
||||
- A DN to bind with. If this is omitted, we'll try a SASL bind with
|
||||
the EXTERNAL mechanism. If this is blank, we'll use an anonymous
|
||||
bind.
|
||||
bind_pw:
|
||||
required: false
|
||||
default: null
|
||||
description:
|
||||
- The password to use with I(bind_dn).
|
||||
dn:
|
||||
required: true
|
||||
description:
|
||||
- The DN of the entry to modify.
|
||||
server_uri:
|
||||
required: false
|
||||
default: ldapi:///
|
||||
description:
|
||||
- A URI to the LDAP server. The default value lets the underlying
|
||||
LDAP client library look for a UNIX domain socket in its default
|
||||
location.
|
||||
start_tls:
|
||||
required: false
|
||||
choices: ['yes', 'no']
|
||||
default: 'no'
|
||||
description:
|
||||
- If true, we'll use the START_TLS LDAP extension.
|
||||
state:
|
||||
required: false
|
||||
choices: [present, absent, exact]
|
||||
default: present
|
||||
description:
|
||||
- The state of the attribute values. If C(present), all given
|
||||
values will be added if they're missing. If C(absent), all given
|
||||
values will be removed if present. If C(exact), the set of values
|
||||
will be forced to exactly those provided and no others. If
|
||||
I(state=exact) and I(value) is empty, all values for this
|
||||
attribute will be removed.
|
||||
attributes:
|
||||
required: true
|
||||
description:
|
||||
- The attribute(s) and value(s) to add or remove. The complex argument
|
||||
format is required in order to pass a list of strings (see examples).
|
||||
ordered:
|
||||
required: false
|
||||
choices: ['yes', 'no']
|
||||
default: 'no'
|
||||
description:
|
||||
- If C(yes), prepend list values with X-ORDERED index numbers in all
|
||||
attributes specified in the current task. This is useful mostly with
|
||||
I(olcAccess) attribute to easily manage LDAP Access Control Lists.
|
||||
validate_certs:
|
||||
required: false
|
||||
choices: ['yes', 'no']
|
||||
default: 'yes'
|
||||
description:
|
||||
- If C(no), SSL certificates will not be validated. This should only be
|
||||
used on sites using self-signed certificates.
|
||||
"""
|
||||
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Configure directory number 1 for example.com
|
||||
ldap_attrs:
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
attributes:
|
||||
olcSuffix: dc=example,dc=com
|
||||
state: exact
|
||||
|
||||
# The complex argument format is required here to pass a list of ACL strings.
|
||||
- name: Set up the ACL
|
||||
ldap_attrs:
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
attributes:
|
||||
olcAccess:
|
||||
- >-
|
||||
{0}to attrs=userPassword,shadowLastChange
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=admin,dc=example,dc=com" write
|
||||
by * none'
|
||||
- >-
|
||||
{1}to dn.base="dc=example,dc=com"
|
||||
by dn="cn=admin,dc=example,dc=com" write
|
||||
by * read
|
||||
state: exact
|
||||
|
||||
# An alternative approach with automatic X-ORDERED numbering
|
||||
- name: Set up the ACL
|
||||
ldap_attrs:
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
attributes:
|
||||
olcAccess:
|
||||
- >-
|
||||
to attrs=userPassword,shadowLastChange
|
||||
by self write
|
||||
by anonymous auth
|
||||
by dn="cn=admin,dc=example,dc=com" write
|
||||
by * none'
|
||||
- >-
|
||||
to dn.base="dc=example,dc=com"
|
||||
by dn="cn=admin,dc=example,dc=com" write
|
||||
by * read
|
||||
ordered: yes
|
||||
state: exact
|
||||
|
||||
- name: Declare some indexes
|
||||
ldap_attrs:
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
attributes:
|
||||
olcDbIndex:
|
||||
- objectClass eq
|
||||
- uid eq
|
||||
|
||||
- name: Set up a root user, which we can use later to bootstrap the directory
|
||||
ldap_attrs:
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
attributes:
|
||||
olcRootDN: cn=root,dc=example,dc=com
|
||||
olcRootPW: "{SSHA}tabyipcHzhwESzRaGA7oQ/SDoBZQOGND"
|
||||
state: exact
|
||||
|
||||
- name: Get rid of an unneeded attribute
|
||||
ldap_attrs:
|
||||
dn: uid=jdoe,ou=people,dc=example,dc=com
|
||||
attributes:
|
||||
shadowExpire: ""
|
||||
state: exact
|
||||
server_uri: ldap://localhost/
|
||||
bind_dn: cn=admin,dc=example,dc=com
|
||||
bind_pw: password
|
||||
|
||||
#
|
||||
# The same as in the previous example but with the authentication details
|
||||
# stored in the ldap_auth variable:
|
||||
#
|
||||
# ldap_auth:
|
||||
# server_uri: ldap://localhost/
|
||||
# bind_dn: cn=admin,dc=example,dc=com
|
||||
# bind_pw: password
|
||||
- name: Get rid of an unneeded attribute
|
||||
ldap_attrs:
|
||||
dn: uid=jdoe,ou=people,dc=example,dc=com
|
||||
attributes:
|
||||
shadowExpire: ""
|
||||
state: exact
|
||||
params: "{{ ldap_auth }}"
|
||||
"""
|
||||
|
||||
|
||||
RETURN = """
|
||||
modlist:
|
||||
description: list of modified parameters
|
||||
returned: success
|
||||
type: list
|
||||
sample: '[[2, "olcRootDN", ["cn=root,dc=example,dc=com"]]]'
|
||||
"""
|
||||
|
||||
|
||||
class LdapAttr(object):
|
||||
def __init__(self, module):
|
||||
# Shortcuts
|
||||
self.module = module
|
||||
self.bind_dn = self.module.params['bind_dn']
|
||||
self.bind_pw = self.module.params['bind_pw']
|
||||
self.dn = self.module.params['dn']
|
||||
self.server_uri = self.module.params['server_uri']
|
||||
self.start_tls = self.module.params['start_tls']
|
||||
self.state = self.module.params['state']
|
||||
self.verify_cert = self.module.params['validate_certs']
|
||||
self.attrs = self.module.params['attributes']
|
||||
self.ordered = self.module.params['ordered']
|
||||
|
||||
# Establish connection
|
||||
self.connection = self._connect_to_ldap()
|
||||
|
||||
def _order_values(self, values):
|
||||
""" Prepend X-ORDERED index numbers to attribute's values. """
|
||||
ordered_values = []
|
||||
|
||||
if isinstance(values, list):
|
||||
for index, value in enumerate(values):
|
||||
cleaned_value = re.sub(r'^\{\d+\}', '', value)
|
||||
ordered_values.append('{' + str(index) + '}' + cleaned_value)
|
||||
|
||||
return ordered_values
|
||||
|
||||
def _normalize_values(self, values):
|
||||
""" Normalize attribute's values. """
|
||||
norm_values = []
|
||||
|
||||
if isinstance(values, list):
|
||||
if self.ordered:
|
||||
norm_values = list(map(to_bytes,
|
||||
self._order_values(list(map(str,
|
||||
values)))))
|
||||
else:
|
||||
norm_values = list(map(to_bytes, values))
|
||||
elif values != "":
|
||||
norm_values = [to_bytes(str(values))]
|
||||
|
||||
return norm_values
|
||||
|
||||
def add(self):
|
||||
modlist = []
|
||||
for name, values in self.module.params['attributes'].items():
|
||||
norm_values = self._normalize_values(values)
|
||||
for value in norm_values:
|
||||
if self._is_value_absent(name, value):
|
||||
modlist.append((ldap.MOD_ADD, name, value))
|
||||
|
||||
return modlist
|
||||
|
||||
def delete(self):
|
||||
modlist = []
|
||||
for name, values in self.module.params['attributes'].items():
|
||||
norm_values = self._normalize_values(values)
|
||||
for value in norm_values:
|
||||
if self._is_value_present(name, value):
|
||||
modlist.append((ldap.MOD_DELETE, name, value))
|
||||
|
||||
return modlist
|
||||
|
||||
def exact(self):
|
||||
modlist = []
|
||||
for name, values in self.module.params['attributes'].items():
|
||||
norm_values = self._normalize_values(values)
|
||||
try:
|
||||
results = self.connection.search_s(
|
||||
self.dn, ldap.SCOPE_BASE, attrlist=[name])
|
||||
except ldap.LDAPError as e:
|
||||
self.module.fail_json(
|
||||
msg="Cannot search for attribute %s" % name,
|
||||
details=to_native(e))
|
||||
|
||||
current = results[0][1].get(name, [])
|
||||
|
||||
if frozenset(norm_values) != frozenset(current):
|
||||
if len(current) == 0:
|
||||
modlist.append((ldap.MOD_ADD, name, norm_values))
|
||||
elif len(norm_values) == 0:
|
||||
modlist.append((ldap.MOD_DELETE, name, None))
|
||||
else:
|
||||
modlist.append((ldap.MOD_REPLACE, name, norm_values))
|
||||
|
||||
return modlist
|
||||
|
||||
def _is_value_present(self, name, value):
|
||||
""" True if the target attribute has the given value. """
|
||||
try:
|
||||
is_present = bool(
|
||||
self.connection.compare_s(self.dn, name, value))
|
||||
except ldap.NO_SUCH_ATTRIBUTE:
|
||||
is_present = False
|
||||
|
||||
return is_present
|
||||
|
||||
def _is_value_absent(self, name, value):
|
||||
""" True if the target attribute doesn't have the given value. """
|
||||
return not self._is_value_present(name, value)
|
||||
|
||||
def _connect_to_ldap(self):
|
||||
if not self.verify_cert:
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
|
||||
connection = ldap.initialize(self.server_uri)
|
||||
|
||||
if self.start_tls:
|
||||
try:
|
||||
connection.start_tls_s()
|
||||
except ldap.LDAPError as e:
|
||||
self.module.fail_json(msg="Cannot start TLS.",
|
||||
details=to_native(e))
|
||||
|
||||
try:
|
||||
if self.bind_dn is not None:
|
||||
connection.simple_bind_s(self.bind_dn, self.bind_pw)
|
||||
else:
|
||||
connection.sasl_interactive_bind_s('', ldap.sasl.external())
|
||||
except ldap.LDAPError as e:
|
||||
self.module.fail_json(
|
||||
msg="Cannot bind to the server.", details=to_native(e))
|
||||
|
||||
return connection
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec={
|
||||
'bind_dn': dict(default=None),
|
||||
'bind_pw': dict(default='', no_log=True),
|
||||
'dn': dict(required=True),
|
||||
'params': dict(type='dict'),
|
||||
'server_uri': dict(default='ldapi:///'),
|
||||
'start_tls': dict(default=False, type='bool'),
|
||||
'state': dict(
|
||||
default='present',
|
||||
choices=['present', 'absent', 'exact']),
|
||||
'attributes': dict(required=True, type='dict'),
|
||||
'ordered': dict(default=False, type='bool'),
|
||||
'validate_certs': dict(default=True, type='bool'),
|
||||
},
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
if not HAS_LDAP:
|
||||
module.fail_json(
|
||||
msg="Missing required 'ldap' module (pip install python-ldap)")
|
||||
|
||||
# Update module parameters with user's parameters if defined
|
||||
if 'params' in module.params and isinstance(module.params['params'], dict):
|
||||
module.params.update(module.params['params'])
|
||||
# Remove the params
|
||||
module.params.pop('params', None)
|
||||
|
||||
# Instantiate the LdapAttr object
|
||||
ldap = LdapAttr(module)
|
||||
|
||||
state = module.params['state']
|
||||
|
||||
# Perform action
|
||||
if state == 'present':
|
||||
modlist = ldap.add()
|
||||
elif state == 'absent':
|
||||
modlist = ldap.delete()
|
||||
elif state == 'exact':
|
||||
modlist = ldap.exact()
|
||||
|
||||
changed = False
|
||||
|
||||
if len(modlist) > 0:
|
||||
changed = True
|
||||
|
||||
if not module.check_mode:
|
||||
try:
|
||||
ldap.connection.modify_s(ldap.dn, modlist)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Attribute action failed.",
|
||||
details=to_native(e),
|
||||
exception=traceback.format_exc())
|
||||
|
||||
module.exit_json(changed=changed, modlist=modlist)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
# Copyright (C) 2021 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2021 DebOps <https://debops.org/>
|
||||
#
|
||||
# Based on community.general.dig, which is:
|
||||
# (c) 2015, Jan-Piet Mens <jpmens(at)gmail.com>
|
||||
# (c) 2017 Ansible Project
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from operator import itemgetter
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
try:
|
||||
import dns.exception
|
||||
import dns.name
|
||||
import dns.resolver
|
||||
import dns.reversename
|
||||
import dns.rdataclass
|
||||
from dns.rdatatype import SRV
|
||||
except ImportError:
|
||||
raise AnsibleError("dig_srv: dnspython library is not installed")
|
||||
|
||||
|
||||
def make_rdata_dict(rdata):
|
||||
supported_types = {
|
||||
SRV: ['priority', 'weight', 'port', 'target'],
|
||||
}
|
||||
|
||||
rd = {}
|
||||
|
||||
if rdata.rdtype not in supported_types:
|
||||
raise AnsibleError("dig_srv: unknown rdtype returned")
|
||||
|
||||
fields = supported_types[rdata.rdtype]
|
||||
for f in fields:
|
||||
val = rdata.__getattribute__(f)
|
||||
|
||||
if isinstance(val, dns.name.Name):
|
||||
val = dns.name.Name.to_text(val)
|
||||
|
||||
if f == "target":
|
||||
rd[f] = val.rstrip('.')
|
||||
else:
|
||||
rd[f] = val
|
||||
|
||||
return rd
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
if len(terms) != 3:
|
||||
raise AnsibleError("dig_srv: three arguments expected")
|
||||
|
||||
myres = dns.resolver.Resolver(configure=True)
|
||||
edns_size = 4096
|
||||
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)
|
||||
|
||||
domain = terms[0]
|
||||
if not domain.endswith('.'):
|
||||
domain += '.'
|
||||
default_domain = terms[1]
|
||||
default_port = terms[2]
|
||||
qtype = 'SRV'
|
||||
rdclass = dns.rdataclass.from_text('IN')
|
||||
|
||||
ret = []
|
||||
|
||||
try:
|
||||
answers = myres.query(domain, qtype, rdclass=rdclass)
|
||||
for rdata in answers:
|
||||
try:
|
||||
rd = make_rdata_dict(rdata)
|
||||
rd['owner'] = answers.canonical_name.to_text().rstrip('.')
|
||||
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
|
||||
rd['ttl'] = answers.rrset.ttl
|
||||
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)
|
||||
rd['dig_srv_src'] = 'dns'
|
||||
ret.append(rd)
|
||||
|
||||
except Exception as e:
|
||||
raise AnsibleError("dig_srv: can't parse response %s" % to_native(e))
|
||||
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
ret.append({
|
||||
"class": "IN",
|
||||
"owner": domain.rstrip('.'),
|
||||
"port": default_port,
|
||||
"priority": 0,
|
||||
"target": default_domain,
|
||||
"ttl": 0,
|
||||
"type": "SRV",
|
||||
"weight": 0,
|
||||
"dig_srv_src": "fallback"
|
||||
})
|
||||
except dns.resolver.Timeout:
|
||||
raise AnsibleError("dig_srv: timeout")
|
||||
except dns.exception.DNSException as e:
|
||||
raise AnsibleError("dig_srv: unhandled exception %s" % to_native(e))
|
||||
|
||||
for r in ret:
|
||||
r.update({"target_port": r["target"] + ":" + str(r["port"])})
|
||||
|
||||
# This is in reverse order of importance, i.e. least important first.
|
||||
# Note that the TTL field shows the remaining TTL when a RR is cached,
|
||||
# so sorting on that field is not a good idea.
|
||||
ret.sort(key=itemgetter("port"))
|
||||
ret.sort(key=itemgetter("target"))
|
||||
ret.sort(key=itemgetter("weight"), reverse=True)
|
||||
ret.sort(key=itemgetter("priority"))
|
||||
|
||||
return ret
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
# (c) 2015, Robert Chady <rchady@sitepen.com>
|
||||
# Based on `runner/lookup_plugins/file.py` for Ansible
|
||||
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This file is part of Debops.
|
||||
# This file is NOT part of Ansible yet.
|
||||
#
|
||||
# Debops is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Debops. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
This file implements the `file_src` lookup filter for Ansible. In difference
|
||||
to the `file` filter, this searches values based on the `file-paths`
|
||||
variable (colon separated) as configured in DebOps.
|
||||
|
||||
NOTE: This means this filter relies on DebOps.
|
||||
|
||||
'''
|
||||
|
||||
__author__ = "Robert Chady <rchady@sitepen.com>"
|
||||
__copyright__ = "Copyright 2015 by Robert Chady <rchady@sitepen.com>"
|
||||
__license__ = "GNU General Public LIcense version 3 (GPL v3) or later"
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import debops
|
||||
debops_version = debops.__version__.__version__
|
||||
conf_section = 'override_paths'
|
||||
conf_key = 'files_path'
|
||||
except AttributeError:
|
||||
try:
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
debops_version = '2.3.0'
|
||||
conf_section = 'paths'
|
||||
conf_key = 'file-paths'
|
||||
except ImportError:
|
||||
pass
|
||||
except ModuleNotFoundError:
|
||||
conf_section = ''
|
||||
conf_key = ''
|
||||
pass
|
||||
|
||||
try:
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
except ImportError:
|
||||
LookupBase = object
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
from ansible import __version__ as __ansible_version__
|
||||
|
||||
|
||||
if LooseVersion(__ansible_version__) < LooseVersion("2.0"):
|
||||
from ansible import utils, errors
|
||||
|
||||
class LookupModule(object):
|
||||
|
||||
def __init__(self, basedir, *args, **kwargs):
|
||||
self.basedir = basedir
|
||||
|
||||
def run(self, terms, inject=None, **kwargs):
|
||||
|
||||
terms = utils.listify_lookup_plugin_terms(
|
||||
terms, self.basedir, inject)
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if '_original_file' in inject:
|
||||
relative_path = utils.path_dwim_relative(
|
||||
inject['_original_file'], 'files',
|
||||
'', self.basedir, check=False)
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise errors.AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
||||
else:
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if 'role_path' in variables:
|
||||
relative_path = self._loader.path_dwim_relative(
|
||||
variables['role_path'], 'files', '')
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
# Copyright (C) 2012 Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# Copyright (C) 2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# Based on `runner/lookup_plugins/items.py` for Ansible
|
||||
#
|
||||
# This file is part of Debops.
|
||||
# This file is NOT part of Ansible yet.
|
||||
#
|
||||
# Debops is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Debops. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
This file implements the `with_lists` lookup filter for Ansible. In
|
||||
differenceto `with_items`, this one does *not* flatten the lists passed to.
|
||||
|
||||
Example:
|
||||
|
||||
- debug: msg="{{item.0}} -- {{item.1}} -- {{item.2}}"
|
||||
with_lists:
|
||||
- ["General", "Verbosity", "0"]
|
||||
- ["Mapping", "Nobody-User", "nobody"]
|
||||
- ["Mapping", "Nobody-Group", "nogroup"]
|
||||
|
||||
Output (shortened):
|
||||
"msg": "General -- Verbosity -- 0"
|
||||
"msg": "Mapping -- Nobody-User -- nobody"
|
||||
"msg": "Mapping -- Nobody-Group -- nogroup"
|
||||
'''
|
||||
|
||||
import ansible.utils as utils
|
||||
import ansible.errors as errors
|
||||
|
||||
try:
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
except ImportError:
|
||||
LookupBase = object
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def __init__(self, basedir=None, **kwargs):
|
||||
self.basedir = basedir
|
||||
|
||||
def run(self, terms, inject=None, **kwargs):
|
||||
terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject)
|
||||
|
||||
if not isinstance(terms, (list, set)):
|
||||
raise errors.AnsibleError("with_list expects a list or a set")
|
||||
|
||||
for i, elem in enumerate(terms):
|
||||
if not isinstance(elem, (list, tuple)):
|
||||
raise errors.AnsibleError(
|
||||
"with_list expects a list (or a set) of lists"
|
||||
" or tuples, but elem %i is not")
|
||||
|
||||
return terms
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
# (c) 2015, Robert Chady <rchady@sitepen.com>
|
||||
# Based on `runner/lookup_plugins/file.py` for Ansible
|
||||
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This file is part of Debops.
|
||||
# This file is NOT part of Ansible yet.
|
||||
#
|
||||
# Debops is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Debops. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
This file implements the `task_src` lookup filter for Ansible. In difference
|
||||
to the `file` filter, this searches values based on the `task-paths`
|
||||
variable (colon separated) as configured in DebOps.
|
||||
|
||||
NOTE: This means this filter relies on DebOps.
|
||||
|
||||
'''
|
||||
|
||||
__author__ = "Robert Chady <rchady@sitepen.com>"
|
||||
__copyright__ = "Copyright 2015 by Robert Chady <rchady@sitepen.com>"
|
||||
__license__ = "GNU General Public LIcense version 3 (GPL v3) or later"
|
||||
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import debops
|
||||
debops_version = debops.__version__.__version__
|
||||
conf_section = 'override_paths'
|
||||
conf_key = 'tasks_path'
|
||||
except AttributeError:
|
||||
try:
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
debops_version = '2.3.0'
|
||||
conf_section = 'paths'
|
||||
conf_key = 'task-paths'
|
||||
except ImportError:
|
||||
pass
|
||||
except ModuleNotFoundError:
|
||||
conf_section = ''
|
||||
conf_key = ''
|
||||
pass
|
||||
|
||||
try:
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
except ImportError:
|
||||
LookupBase = object
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
from ansible import __version__ as __ansible_version__
|
||||
|
||||
|
||||
if LooseVersion(__ansible_version__) < LooseVersion("2.0"):
|
||||
from ansible import utils, errors
|
||||
|
||||
class LookupModule(object):
|
||||
|
||||
def __init__(self, basedir, *args, **kwargs):
|
||||
self.basedir = basedir
|
||||
|
||||
def run(self, terms, inject=None, **kwargs):
|
||||
|
||||
terms = utils.listify_lookup_plugin_terms(
|
||||
terms, self.basedir, inject)
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if '_original_file' in inject:
|
||||
relative_path = utils.path_dwim_relative(
|
||||
inject['_original_file'], 'tasks', '',
|
||||
self.basedir, check=False)
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise errors.AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
||||
else:
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if 'role_path' in variables:
|
||||
relative_path = (
|
||||
self._loader.path_dwim_relative(
|
||||
variables['role_path'],
|
||||
'tasks', ''))
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
# (c) 2015, Robert Chady <rchady@sitepen.com>
|
||||
# Based on `runner/lookup_plugins/file.py` for Ansible
|
||||
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This file is part of Debops.
|
||||
# This file is NOT part of Ansible yet.
|
||||
#
|
||||
# Debops is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Debops. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
This file implements the `template_src` lookup filter for Ansible. In
|
||||
difference to the `template` filter, this searches values based on the
|
||||
`template-paths` variable (colon separated) as configured in DebOps.
|
||||
|
||||
NOTE: This means this filter relies on DebOps.
|
||||
|
||||
'''
|
||||
|
||||
__author__ = "Robert Chady <rchady@sitepen.com>"
|
||||
__copyright__ = "Copyright 2015 by Robert Chady <rchady@sitepen.com>"
|
||||
__license__ = "GNU General Public LIcense version 3 (GPL v3) or later"
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import debops
|
||||
debops_version = debops.__version__.__version__
|
||||
conf_section = 'override_paths'
|
||||
conf_key = 'templates_path'
|
||||
except AttributeError:
|
||||
try:
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
debops_version = '2.3.0'
|
||||
conf_section = 'paths'
|
||||
conf_key = 'template-paths'
|
||||
except ImportError:
|
||||
pass
|
||||
except ModuleNotFoundError:
|
||||
conf_section = ''
|
||||
conf_key = ''
|
||||
pass
|
||||
|
||||
try:
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
except ImportError:
|
||||
LookupBase = object
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
from ansible import __version__ as __ansible_version__
|
||||
|
||||
|
||||
if LooseVersion(__ansible_version__) < LooseVersion("2.0"):
|
||||
from ansible import utils, errors
|
||||
|
||||
class LookupModule(object):
|
||||
|
||||
def __init__(self, basedir, *args, **kwargs):
|
||||
self.basedir = basedir
|
||||
|
||||
def run(self, terms, inject=None, **kwargs):
|
||||
|
||||
terms = utils.listify_lookup_plugin_terms(
|
||||
terms, self.basedir, inject)
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if '_original_file' in inject:
|
||||
relative_path = (
|
||||
utils.path_dwim_relative(
|
||||
inject['_original_file'], 'templates',
|
||||
'', self.basedir, check=False))
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise errors.AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
||||
else:
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
ret = []
|
||||
config = {}
|
||||
places = []
|
||||
|
||||
# this can happen if the variable contains a string,
|
||||
# strictly not desired for lookup plugins, but users may
|
||||
# try it, so make it work.
|
||||
if not isinstance(terms, list):
|
||||
terms = [terms]
|
||||
|
||||
try:
|
||||
project_config = debops.config.Configuration()
|
||||
project_dir = debops.projectdir.ProjectDir(
|
||||
config=project_config)
|
||||
project_root = project_dir.path
|
||||
if project_dir.config.get(['project', 'type']) == 'modern':
|
||||
config = project_dir.config.get([])
|
||||
else:
|
||||
config = project_dir.config.get(['views', 'system'])
|
||||
except NameError:
|
||||
try:
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
except NameError:
|
||||
pass
|
||||
except NotADirectoryError:
|
||||
# This is not a DebOps project directory, so continue as normal
|
||||
pass
|
||||
|
||||
if conf_section in config and conf_key in config[conf_section]:
|
||||
custom_places = (
|
||||
config[conf_section][conf_key].split(':'))
|
||||
for custom_path in custom_places:
|
||||
if os.path.isabs(custom_path):
|
||||
places.append(custom_path)
|
||||
else:
|
||||
places.append(os.path.join(
|
||||
project_root, custom_path))
|
||||
|
||||
for term in terms:
|
||||
if 'role_path' in variables:
|
||||
relative_path = (
|
||||
self._loader.path_dwim_relative(
|
||||
variables['role_path'], 'templates',
|
||||
''))
|
||||
places.append(relative_path)
|
||||
for path in places:
|
||||
template = os.path.join(path, term)
|
||||
if template and os.path.exists(template):
|
||||
ret.append(template)
|
||||
break
|
||||
else:
|
||||
raise AnsibleError(
|
||||
"could not locate file in lookup: %s"
|
||||
% term)
|
||||
|
||||
return ret
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
# Copyright (C) 2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2017-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'A set of custom Ansible plugins used by DebOps roles'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.3.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- ansible
|
||||
- debops
|
||||
19
ansible_collections/debops/debops/roles/apache/COPYRIGHT
Normal file
19
ansible_collections/debops/debops/roles/apache/COPYRIGHT
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
debops.apache - Manage and configure the Apache HTTP Server
|
||||
|
||||
Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
1042
ansible_collections/debops/debops/roles/apache/defaults/main.yml
Normal file
1042
ansible_collections/debops/debops/roles/apache/defaults/main.yml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Test apache and reload
|
||||
ansible.builtin.command: apache2ctl configtest
|
||||
register: apache__register_reload
|
||||
changed_when: apache__register_reload.changed | bool
|
||||
notify: [ 'Reload apache' ]
|
||||
|
||||
# - name: Test apache and restart
|
||||
# ansible.builtin.command: apache2ctl configtest
|
||||
# notify: [ 'Restart apache' ]
|
||||
|
||||
- name: Reload apache
|
||||
ansible.builtin.service:
|
||||
name: '{{ apache__service_name }}'
|
||||
state: 'reloaded'
|
||||
|
||||
## Listed here for completeness but not used.
|
||||
## Refer to ../docs/ansible-integration.rst
|
||||
# - name: Restart apache
|
||||
# ansible.builtin.service:
|
||||
# name: '{{ apache__service_name }}'
|
||||
# state: 'restarted'
|
||||
30
ansible_collections/debops/debops/roles/apache/meta/main.yml
Normal file
30
ansible_collections/debops/debops/roles/apache/meta/main.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
company: 'DebOps'
|
||||
author: 'Robin Schneider'
|
||||
description: 'Manage and configure the Apache HTTP Server'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.3.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- web
|
||||
- webserver
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
# vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Enable/disable Apache modules
|
||||
debops.debops.apache2_module:
|
||||
name: '{{ item.key }}'
|
||||
state: '{{ (item.value.enabled
|
||||
if (item.value is mapping)
|
||||
else item.value) | bool | ternary("present", "absent") }}'
|
||||
force: '{{ item.value.force | d(False) | bool }}'
|
||||
notify: [ 'Test apache and reload' ]
|
||||
when: (item.key in apache__tpl_available_modules
|
||||
and item.value.enabled | d(True) != omit
|
||||
and apache__deploy_state == "present")
|
||||
with_dict: '{{ apache__combined_modules }}'
|
||||
tags: [ 'role::apache:modules' ]
|
||||
170
ansible_collections/debops/debops/roles/apache/tasks/main.yml
Normal file
170
ansible_collections/debops/debops/roles/apache/tasks/main.yml
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import custom Ansible plugins
|
||||
ansible.builtin.import_role:
|
||||
name: 'ansible_plugins'
|
||||
|
||||
# Manage optional system packages [[[1
|
||||
- name: Ensure optional packages are in there desired state
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", (apache__packages
|
||||
+ apache__group_packages
|
||||
+ apache__host_packages
|
||||
+ apache__dependent_packages)) }}'
|
||||
state: '{{ "present" if (apache__deploy_state == "present") else "absent" }}'
|
||||
register: apache__register_packages
|
||||
until: apache__register_packages is succeeded
|
||||
|
||||
# Manage Apache modules [[[1
|
||||
- name: Get list of available modules
|
||||
ansible.builtin.find:
|
||||
file_type: 'file'
|
||||
paths: [ '{{ apache__config_path + "/mods-available/" }}' ]
|
||||
patterns: [ '*.load' ]
|
||||
register: apache__register_mods_available
|
||||
tags: [ 'role::apache:modules' ]
|
||||
|
||||
- name: Set list of available modules
|
||||
ansible.builtin.set_fact:
|
||||
apache__tpl_available_modules: '{{ apache__register_mods_available.files | d({})
|
||||
| map(attribute="path")
|
||||
| map("replace", apache__config_path + "/mods-available/", "")
|
||||
| map("regex_replace", "\.load$", "") | list }}'
|
||||
tags: [ 'role::apache:modules' ]
|
||||
|
||||
- name: Configure Apache module state
|
||||
ansible.builtin.include_tasks: apache_module_state.yml
|
||||
|
||||
# Manage Apache configuration snippets [[[1
|
||||
- name: Divert conf-available configuration
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ apache__config_path + "/conf-available/" + item.key + ".conf" }}'
|
||||
divert: '{{ (item.value.divert
|
||||
| d(apache__config_path + "/conf-available/"
|
||||
+ (item.value.divert_filename | d(item.key)) + ".conf"))
|
||||
+ item.value.divert_suffix | d(".dpkg-divert") }}'
|
||||
when: (item.value.type | d("default") in ["divert"])
|
||||
with_dict: '{{ apache__combined_snippets }}'
|
||||
|
||||
- name: Remove conf-available snippets
|
||||
ansible.builtin.file:
|
||||
path: '{{ apache__config_path + "/conf-available/" + item.key + ".conf" }}'
|
||||
state: 'absent'
|
||||
when: (item.value.state | d("present") == "absent")
|
||||
with_dict: '{{ apache__combined_snippets }}'
|
||||
tags: [ 'role::apache:vhosts' ]
|
||||
|
||||
- name: Create conf-available snippets
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apache2/conf-available/{{ "raw"
|
||||
if (item.value.type | d("default") in ["divert", "raw"] and
|
||||
item.value.raw | d())
|
||||
else item.key }}.conf.j2'
|
||||
dest: '{{ apache__config_path + "/conf-available/" + item.key + ".conf" }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
when: (item.value.state | d("present") != "absent" and
|
||||
(item.value.type | d("default") not in ["divert", "dont-create"] or item.value.raw | d()))
|
||||
with_dict: '{{ apache__combined_snippets }}'
|
||||
notify: [ 'Test apache and reload' ]
|
||||
|
||||
- name: Enable/disable configuration snippets
|
||||
ansible.builtin.file:
|
||||
path: '{{ apache__config_path + "/conf-enabled/" + item.key + ".conf" }}'
|
||||
src: '{{ (((item.value.enabled | d(True)
|
||||
if (item.value is mapping)
|
||||
else item.value | d(True)))
|
||||
if (item.value.state | d("present") != "absent")
|
||||
else False) | bool
|
||||
| ternary("../conf-available/" + item.key + ".conf",
|
||||
omit) }}'
|
||||
mode: '0644'
|
||||
force: '{{ ansible_check_mode | d() | bool }}'
|
||||
state: '{{ (((item.value.enabled | d(True)
|
||||
if (item.value is mapping)
|
||||
else item.value | d(True)))
|
||||
if (item.value.state | d("present") != "absent")
|
||||
else False) | bool | ternary("link", "absent") }}'
|
||||
when: (item.value.type | d("default") not in ["divert"])
|
||||
with_dict: '{{ apache__combined_snippets }}'
|
||||
notify: [ 'Test apache and reload' ]
|
||||
|
||||
# Manage Apache virtual hosts [[[1
|
||||
- name: Divert sites-available configuration
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ apache__config_path + "/sites-available/"
|
||||
+ item.filename | d([item.name] | flatten | first | d("default"))
|
||||
+ ".conf" }}'
|
||||
divert: '{{ (item.divert
|
||||
| d(apache__config_path + "/sites-available/"
|
||||
+ item.divert_filename | d(item.filename | d([item.name] | flatten | first | d("default")))
|
||||
+ ".conf")
|
||||
+ item.divert_suffix | d(".dpkg-divert")) }}'
|
||||
when: (item.type | d(apache__vhost_type) in ["divert"])
|
||||
loop: '{{ q("flattened", apache__combined_vhosts) }}'
|
||||
|
||||
- name: Remove sites-available configuration
|
||||
ansible.builtin.file:
|
||||
path: '{{ apache__config_path }}/sites-available/{{ item.filename | d(item.name
|
||||
if (item.name is string)
|
||||
else item.name[0] | d("default")) }}.conf'
|
||||
state: 'absent'
|
||||
when: (item.state | d("present") == 'absent')
|
||||
loop: '{{ q("flattened", apache__combined_vhosts) }}'
|
||||
tags: [ 'role::apache:vhosts' ]
|
||||
|
||||
- name: Create sites-available configuration
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apache2/sites-available/{{ item.type | d(apache__vhost_type) }}.conf.j2'
|
||||
dest: '{{ apache__config_path }}/sites-available/{{ item.filename | d(item.name
|
||||
if (item.name is string)
|
||||
else item.name[0] | d("default")) }}.conf'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
notify: [ 'Test apache and reload' ]
|
||||
when: (item.state | d("present") != "absent" and item.type | d(apache__vhost_type) not in ["divert", "dont-create"])
|
||||
loop: '{{ q("flattened", apache__combined_vhosts) }}'
|
||||
tags: [ 'role::apache:vhosts' ]
|
||||
|
||||
- name: Enable/disable Apache virtual hosts
|
||||
ansible.builtin.file:
|
||||
path: '{{ apache__config_path }}/sites-enabled/{{ item.filename | d(item.name
|
||||
if (item.name is string)
|
||||
else item.name[0] | d("default")) }}.conf'
|
||||
src: '{{ ("../sites-available/" + item.filename
|
||||
| d(item.name
|
||||
if (item.name is string)
|
||||
else item.name[0] | d("default")) + ".conf")
|
||||
if (item.enabled | d(True) | bool and (item.state | d("present") != "absent"))
|
||||
else omit }}'
|
||||
force: '{{ item.force | d(ansible_check_mode) | bool }}'
|
||||
state: '{{ item.enabled | d(True) | bool | ternary("link", "absent")
|
||||
if (item.state | d("present") != "absent")
|
||||
else "absent" }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
notify: [ 'Test apache and reload' ]
|
||||
when: (item.type | d(apache__vhost_type) not in ["divert"])
|
||||
loop: '{{ q("flattened", apache__combined_vhosts) }}'
|
||||
tags: [ 'role::apache:vhosts' ]
|
||||
|
||||
|
||||
# Manage Apache modules, part 2 [[[1
|
||||
- name: Detect if the rewrite module has been used in the active configuration
|
||||
ansible.builtin.shell: grep --recursive --ignore-case '^\s*RewriteEngine On' {{ apache__config_path | quote }}
|
||||
register: apache__register_mod_rewrite_used
|
||||
check_mode: False
|
||||
failed_when: apache__register_mod_rewrite_used.rc not in [0, 1]
|
||||
changed_when: False
|
||||
when: apache__register_mod_rewrite_used is undefined
|
||||
|
||||
- name: Finish configuration of Apache module state
|
||||
ansible.builtin.include_tasks: apache_module_state.yml
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
# Manage required system packages [[[1
|
||||
- name: Ensure base packages are in there desired state
|
||||
ansible.builtin.package:
|
||||
name: '{{ item }}'
|
||||
state: '{{ "present" if (apache__deploy_state == "present") else "absent" }}'
|
||||
loop: '{{ q("flattened", apache__base_packages) }}'
|
||||
register: apache__register_base_packages
|
||||
until: apache__register_base_packages is succeeded
|
||||
tags: [ 'role::apache:pkgs' ]
|
||||
|
||||
# Ansible facts [[[1
|
||||
- name: Make sure Ansible fact directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Create local facts of Apache
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apache.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apache.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
notify: [ 'Refresh host facts' ]
|
||||
|
||||
- name: Reload facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import loads, dumps
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
output = loads('''{{ ({
|
||||
"enabled": (apache__deploy_state == "present"),
|
||||
"user": apache__user,
|
||||
"use_if_version": apache__config_use_if_version,
|
||||
"min_version": apache__config_min_version,
|
||||
}) | to_nice_json }}''')
|
||||
|
||||
try:
|
||||
apache_v = subprocess.check_output(
|
||||
['apache2', '-v']).decode('utf-8').split('\n')
|
||||
|
||||
for line in apache_v:
|
||||
_re = re.match(r'Server version: Apache/(?P<version>[^ ]+)', line)
|
||||
if _re:
|
||||
output['version'] = _re.group('version')
|
||||
|
||||
if output['use_if_version']:
|
||||
if output['min_version'] == 'current_major_minor':
|
||||
output['min_version'] = '.'.join(
|
||||
output['version'].split('.')[:2])
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
# vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
{% macro get_yaml_list_for_elem(list_or_elem) %}{# [[[ #}
|
||||
{{ ([ list_or_elem ]
|
||||
if (list_or_elem is string or list_or_elem in [True, False])
|
||||
else (list_or_elem | list)) | to_nice_yaml }}
|
||||
{% endmacro %}
|
||||
{% macro get_realm_yaml_list(domains, fallback_realm) %}{# [[[ #}
|
||||
{% set custom_realm_list = [] %}
|
||||
{% if domains and (ansible_local.pki.known_realms | d()) %}
|
||||
{% for domain in (get_yaml_list_for_elem(domains) | from_yaml) %}
|
||||
{% if domain in ansible_local.pki.known_realms %}
|
||||
{% set _ = custom_realm_list.append(domain) %}
|
||||
{% elif (domain.split('.')[1:] | join('.')) in ansible_local.pki.known_realms %}
|
||||
{% set _ = custom_realm_list.append(domain.split('.')[1:] | join('.')) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if custom_realm_list | length == 0 %}
|
||||
{% set _ = custom_realm_list.append(fallback_realm) %}
|
||||
{% endif %}
|
||||
{{ custom_realm_list | to_nice_yaml }}
|
||||
{% endmacro %}
|
||||
{% macro get_apache_version() %}{# [[[ #}
|
||||
{{ ansible_local.apache.version | d("2.4.0") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_apache_min_version() %}{# [[[ #}
|
||||
{{ ansible_local.apache.min_version | d("2.4.0") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_openssl_version() %}{# [[[ #}
|
||||
{{ ansible_local.pki.openssl_version | d("1.0.2") }}
|
||||
{% endmacro %}
|
||||
{% macro get_gnutls_version() %}{# [[[ #}
|
||||
{{ ansible_local.pki.gnutls_version | d("0.0.0") }}
|
||||
{% endmacro %}
|
||||
{% macro debops_indent(content, width=4, indentfirst=False) %}{# [[[ #}
|
||||
{# Fixed version of the `indent` filter which does not insert trailing spaces on empty lines.
|
||||
## Note that you can not use this macro like a filter but have to use it like a regular macro.
|
||||
## Example: {{ indent(some_content, 4) }}
|
||||
##
|
||||
## Python re.sub seems to default to re.MULTILINE in Ansible.
|
||||
#}
|
||||
{{ content | indent(width, indentfirst) | regex_replace("[ \\t\\r\\f\\v]+(\\n|$)", "\\1") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_min_version_wrapped(content, version, compare_operator) %}{# [[[ #}
|
||||
{# Examples:
|
||||
|
||||
{{ get_min_version_wrapped('# 2.3.0 directive', "2.3", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.4.0 directive', "2.4", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.4.1 directive', "2.4.1", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.5.0 directive', "2.5", ">=") }}
|
||||
|
||||
#}
|
||||
{% set version = '==' if (version == '=') else version %}
|
||||
{% set apache__tpl_compare_operator_includes_equal = True if (compare_operator in ['>=', '<=', '==']) else False %}
|
||||
{% if (version is version_compare(get_apache_min_version(), compare_operator))
|
||||
or (version is version_compare(get_apache_min_version(), ">")) %}
|
||||
{% if apache__tpl_compare_operator_includes_equal and (version is version_compare(get_apache_min_version(), "==")) %}
|
||||
{{ content -}}
|
||||
{% else %}
|
||||
<IfVersion {{ compare_operator }} {{ version }}>
|
||||
{{ debops_indent(content, 4) }}
|
||||
</IfVersion>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_version_wrapped(content, version, compare_operator, fallback_content=False) %}{# [[[ #}
|
||||
{# This macro has not been extensively tested yet. If it contains bugs please try to debug it if you need it.
|
||||
|
||||
Examples:
|
||||
|
||||
{{ get_version_wrapped('# 2.3.0 directive', "2.3", ">=", '# Prior to 2.3 directive') }}
|
||||
{{ get_version_wrapped('# 2.4.0 directive', "2.4", ">=", '# Prior to 2.4 directive') }}
|
||||
{{ get_version_wrapped('# 2.4.1 directive', "2.4.1", ">=", '# Prior to 2.4.1 directive') }}
|
||||
{{ get_version_wrapped('# 2.5.0 directive', "2.5", ">=", '# Prior to 2.5 directive') }}
|
||||
|
||||
#}
|
||||
{% set version = '==' if (version == '=') else version %}
|
||||
{% set apache__tpl_xor_compare_operator_map = {} %}
|
||||
{% set apache__tpl_xor_compare_operator_list = [
|
||||
('==', '!='),
|
||||
('>=', '<'),
|
||||
('<=', '>'),
|
||||
] %}
|
||||
{% for compare_operator, xor_compare_operator in apache__tpl_xor_compare_operator_list %}
|
||||
{% set _ = apache__tpl_xor_compare_operator_map.update({ compare_operator: xor_compare_operator }) %}
|
||||
{% set _ = apache__tpl_xor_compare_operator_map.update({ xor_compare_operator: compare_operator }) %}
|
||||
{% endfor %}
|
||||
{% if apache__config_use_if_version | bool %}
|
||||
{{ get_min_version_wrapped(content, version, compare_operator) -}}
|
||||
{% if fallback_content != False %}
|
||||
{{ get_min_version_wrapped(fallback_content, version, apache__tpl_xor_compare_operator_map[compare_operator]) -}}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if get_apache_version() is version_compare(version, compare_operator) %}
|
||||
{{ content -}}
|
||||
{% elif fallback_content != False %}
|
||||
{{ fallback_content -}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_server_name_aliases(name_item) %}{# [[[ #}
|
||||
{% set apache__tpl_names = get_yaml_list_for_elem(name_item) | from_yaml %}
|
||||
{% if not apache__tpl_names %}
|
||||
{% set apache__tpl_names = [ apache__server_name ] %}
|
||||
{% endif %}
|
||||
ServerName {{ apache__tpl_names[0] | quote }}
|
||||
{% if apache__tpl_names | length > 1 %}
|
||||
ServerAlias {{ apache__tpl_names[1:] | map("quote") | join(" ") }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_listen_sockets(item_listen_list, server_port_listen_list) %}{# [[[ #}
|
||||
{% set apache__tpl_listen_sockets = [] %}
|
||||
{% if item_listen_list | length == 0 %}
|
||||
{% set item_listen_list = server_port_listen_list %}
|
||||
{% endif %}
|
||||
{% for item_listen in item_listen_list %}
|
||||
{% if ':' not in item_listen | string %}
|
||||
{# {% if item_listen in server_port_listen_list %}
|
||||
## Apparently, this is not even needed for Apache to (re)start without issues. #}
|
||||
{% set _ = apache__tpl_listen_sockets.append("*:" + item_listen | string) %}
|
||||
{% else %}
|
||||
{% set _ = apache__tpl_listen_sockets.append(item_listen | string) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ apache__tpl_listen_sockets | join(" ") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_header_comments(item) %}{# [[[ #}
|
||||
{% if item.by_role | d() %}
|
||||
|
||||
# Generated by Ansible role: {{ item.by_role }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_server_directives(item) %}{# [[[ #}
|
||||
{% set sanitized_name = (get_yaml_list_for_elem(item.filename | d(item.name)) | from_yaml)[0] | replace(".", "_") %}
|
||||
{% if item.name | d([]) %}
|
||||
{{ get_server_name_aliases(item.name | d([])) }}
|
||||
{% endif %}
|
||||
ServerAdmin {{ item.server_admin | d(apache__server_admin) | quote }}
|
||||
CustomLog {{ item.custom_log | d('${APACHE_LOG_DIR}/' + sanitized_name + '_access.log' + ' ' + apache__access_log_format + ' ' + item.custom_log_condition | d()) }}
|
||||
ErrorLog {{ item.error_log | d('${APACHE_LOG_DIR}/' + sanitized_name + '_error.log') }}
|
||||
{% endmacro %}
|
||||
{% macro get_server_status_directives(item, enabled) %}{# [[[ #}
|
||||
{% if enabled | bool %}
|
||||
<Location {{ item.status_location | d(apache__status_location) | quote }}>
|
||||
SetHandler server-status
|
||||
{% if item.status_allow_localhost | d(apache__status_allow_localhost) | bool %}
|
||||
Require local
|
||||
{% endif %}
|
||||
{% if item.status_directives | d(apache__status_directives) %}
|
||||
{{ item.status_directives | d(apache__status_directives) }}
|
||||
{% elif not (item.status_allow_localhost | d(apache__status_allow_localhost) | bool) %}
|
||||
Require all denied
|
||||
{% endif %}
|
||||
</Location>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_vhost_content_directives(item, mode='https', https_enabled=True) %}{# [[[ #}
|
||||
{% set apache__tpl_use_redirect_module = 'alias' %}
|
||||
{% set apache__tpl_status_enabled = item.status_enabled | d(apache__status_for_vhost_enabled) | bool %}
|
||||
{{ get_server_status_directives(item, apache__tpl_status_enabled) -}}
|
||||
{% if apache__tpl_status_enabled | bool and (
|
||||
(mode == 'http' and (item.redirect_http | d() or item.redirect_to_https | d(apache__redirect_to_https) | bool)) or
|
||||
(mode == 'https' and item.redirect_https | d())
|
||||
) %}
|
||||
<IfModule mod_rewrite>
|
||||
RewriteEngine On
|
||||
RewriteRule "^{{ item.status_location | d(apache__status_location) }}" "-" [L]
|
||||
</IfModule>
|
||||
{% set apache__tpl_use_redirect_module = 'rewrite' %}
|
||||
{% endif %}
|
||||
{% if mode == 'http' and item.redirect_http | d() %}
|
||||
{{ get_redirect(item.redirect_http_code | d(307), "/", item.redirect_http, apache__tpl_use_redirect_module) }}
|
||||
{% elif mode == 'http' and item.redirect_to_https | d(apache__redirect_to_https) | bool %}
|
||||
{{ get_redirect(item.redirect_to_https_with_code | d("301"), "/", "https://" + (get_yaml_list_for_elem(item.name) | from_yaml)[0], apache__tpl_use_redirect_module) }}
|
||||
{% elif mode == 'https' and item.redirect_https | d() %}
|
||||
{{ get_redirect(item.redirect_https_code | d(307), "/", item.redirect_https, apache__tpl_use_redirect_module) }}
|
||||
{% else %}
|
||||
{{ get_content_directives(item) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_document_root_directives(item) %}{# [[[ #}
|
||||
Options {{ get_yaml_list_for_elem(item.options | d(apache__vhost_options)) | from_yaml | join(" ") }}
|
||||
AllowOverride {{ get_yaml_list_for_elem(item.allow_override | d(apache__vhost_allow_override)) | from_yaml | join(" ") }}
|
||||
|
||||
{{ get_version_wrapped('Require all granted', "2.4", ">=",
|
||||
'Order allow,deny
|
||||
Allow from all') -}}
|
||||
{% if item.root_directives | d() %}
|
||||
|
||||
{{ item.root_directives }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_content_directives(item) %}{# [[[ #}
|
||||
{% if item.include | d() %}
|
||||
{% for include_file in get_yaml_list_for_elem(item.include) | from_yaml %}
|
||||
Include {{ include_file | quote }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if item.include_optional | d() %}
|
||||
{% for include_optional_file in get_yaml_list_for_elem(item.include_optional) | from_yaml %}
|
||||
IncludeOptional {{ include_optional_file | quote }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if item.root | d(item.document_root | d()) %}
|
||||
DocumentRoot {{ item.root | d(item.document_root) | quote }}
|
||||
|
||||
{% if item.index | d() %}
|
||||
DirectoryIndex {{ get_yaml_list_for_elem(item.index) | from_yaml | join(" ") }}
|
||||
{% endif %}
|
||||
{% if item.alias | d() %}
|
||||
{{ get_alias(item.alias, item.alias_path | d(item.root) | d(item.document_root)) }}
|
||||
{%- endif %}
|
||||
<Directory {{ item.root | d(item.document_root) | quote }}>
|
||||
{{ debops_indent(get_document_root_directives(item), 4) }}
|
||||
</Directory>
|
||||
{% endif %}
|
||||
{% if item.raw_content | d() %}
|
||||
|
||||
{{ item.raw_content }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_default_tls_directives(item) %}{# [[[ #}
|
||||
{# Included in server context to provide sane defaults (there might be vhosts
|
||||
# not controlled by this template) and in virtual host context to ensure those
|
||||
# settings are appliend and to allow per-vhost changes.
|
||||
# Refer to Applied-Crypto-Hardening_bettercrypto/src/configuration/Webservers/Apache/default-ssl for details.
|
||||
#}
|
||||
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||
SSLOptions +StdEnvVars
|
||||
</FilesMatch>
|
||||
<Directory /usr/lib/cgi-bin>
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
|
||||
BrowserMatch "MSIE [2-6]" \
|
||||
nokeepalive ssl-unclean-shutdown \
|
||||
downgrade-1.0 force-response-1.0
|
||||
# MSIE 7 and newer should be able to use keepalive
|
||||
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||
|
||||
# TLS cipher suites set: {{ item.tls_cipher_suite_set_name | d(apache__tls_cipher_suite_set_name) | quote }}
|
||||
SSLCipherSuite {{ apache__tls_cipher_suite_sets[item.tls_cipher_suite_set_name | d(apache__tls_cipher_suite_set_name)] | quote }}
|
||||
SSLProtocol {{ item.tls_protocols | d(apache__tls_protocols) | join(" ") }}
|
||||
SSLHonorCipherOrder {{ item.tls_honor_cipher_order | d(apache__tls_honor_cipher_order) | quote }}
|
||||
SSLCompression {{ item.tls_compression | d(apache__tls_compression) | quote }}
|
||||
|
||||
{#
|
||||
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html
|
||||
# https://github.com/sovereign/sovereign/issues/373
|
||||
#}
|
||||
{% if get_apache_version() is version_compare("2.4.8", ">=") and get_openssl_version() is version_compare("1.0.2", ">=") %}
|
||||
# SSLOpenSSLConfCmd DHParameters {{ item.tls_dhparam_file | d(apache__tls_dhparam_file) | quote }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_https_directives(item) %}{# [[[ #}
|
||||
SSLEngine on
|
||||
|
||||
{{ get_default_tls_directives(item) }}
|
||||
{% set apache__tpl_pki_realm = item.pki_realm | d((get_realm_yaml_list(item.name, apache__pki_realm) | from_yaml)[0]) %}
|
||||
{% set apache__tpl_pki_realm_path = apache__pki_realm_path + "/" + apache__tpl_pki_realm %}
|
||||
SSLCertificateFile {{ item.tls_crt | d(apache__tpl_pki_realm_path + "/" + (item.pki_crt | d(apache__pki_crt_filename))) | quote }}
|
||||
SSLCertificateKeyFile {{ item.tls_key | d(apache__tpl_pki_realm_path + "/" + (item.pki_key | d(apache__pki_key_filename))) | quote }}
|
||||
{% if item.ocsp_stapling_enabled | d(apache__ocsp_stapling_enabled) | bool and get_openssl_version() is version_compare("0.9.8h", ">=") %}
|
||||
SSLUseStapling on
|
||||
{% endif %}
|
||||
|
||||
{% if item.hsts_enabled | d(apache__hsts_enabled) | bool %}
|
||||
Header always set Strict-Transport-Security "max-age={{ item.hsts_max_age | d(apache__hsts_max_age) }}{{ "; includeSubDomains" if item.hsts_subdomains | d(apache__hsts_subdomains) | bool else "" }}{{ "; preload" if ((item.hsts_preload | d(apache__hsts_preload)) | bool) else "" }}"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_http_security_headers(item) %}{# [[[ #}
|
||||
{% set apache__tpl_directive_options = get_yaml_list_for_elem(item.http_sec_headers_directive_options | d(apache__http_sec_headers_directive_options)) | from_yaml | map("quote") | join(" ") %}
|
||||
{% if item.csp_enabled | d(False) | bool %}
|
||||
Header {{ apache__tpl_directive_options }} Content-Security-Policy "{{ item.csp | d("default-src https: ;") + (" " + item.csp_append | d(apache__http_csp_append) if (item.csp_append | d(apache__http_csp_append)) else "") }}"
|
||||
{% endif %}
|
||||
{% if item.csp_report_enabled | d(False) | bool %}
|
||||
Header {{ apache__tpl_directive_options }} Content-Security-Policy-Report-Only "{{ item.csp_report | d(item.csp | d("default-src https: ;")) + (" " + item.csp_append | d(apache__http_csp_append) if (item.csp_append | d(apache__http_csp_append)) else "") }}"
|
||||
{% endif %}
|
||||
{% if item.http_frame_options | d(apache__http_frame_options) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-Frame-Options "{{ item.http_frame_options | d(apache__http_frame_options) }}"
|
||||
{% endif %}
|
||||
{% if item.http_xss_protection | d(apache__http_xss_protection) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-XSS-Protection "{{ item.http_xss_protection | d(apache__http_xss_protection) }}"
|
||||
{% endif %}
|
||||
{% if item.http_referrer_policy | d(apache__http_referrer_policy) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} Referrer-Policy "{{ item.http_referrer_policy | d(apache__http_referrer_policy) }}"
|
||||
{% endif %}
|
||||
{% if item.http_content_type_options | d(apache__http_content_type_options) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-Content-Type-Options "{{ item.http_content_type_options | d(apache__http_content_type_options) }}"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_common_headers(item) %}{# [[[ #}
|
||||
{% if item.http_clacks_overhead | d(apache__http_clacks_overhead | d(True)) | bool %}
|
||||
{#
|
||||
# Respect the will of the DebOps Creator.
|
||||
# Ref: https://github.com/debops/ansible-nginx/commit/d6cd455c68a7584b2592053fd98d3e539054e09a
|
||||
#}
|
||||
Header always set X-Clacks-Overhead "GNU Terry Pratchett"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_redirect(code, from, to, module) %}{# [[[ #}
|
||||
{# Prefer the alias module but support the use of the rewrite module in case
|
||||
other rewrite rules are used in the same context because the rewrite rules are
|
||||
handled before all the directives from the alias module.
|
||||
#}
|
||||
{% set to = to + ("/" if (to[-1] != "/") else "") %}
|
||||
{% if module == 'alias' %}
|
||||
Redirect {{ code | string }} "{{ from }}" "{{ to }}"
|
||||
{% elif module == 'rewrite' %}
|
||||
<IfModule mod_rewrite>
|
||||
RewriteRule "^{{ from }}?(.*)" "{{ to }}$1" [L,R={{ code }},NE]
|
||||
</IfModule>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_alias(url_path, fs_directory) %}{# [[[ #}
|
||||
Alias {{ url_path | quote }} {{ (fs_directory + ("/" if (fs_directory[-1] != "/") else "")) | quote }}
|
||||
{% endmacro %}
|
||||
|
||||
{#
|
||||
# It seems that Apache does not allow to overwrite directives in the same context (server config):
|
||||
# Examples: LogLevel
|
||||
# It is probably not good practice to change that in server context anyway.
|
||||
#}
|
||||
|
||||
MaxConnectionsPerChild {{ apache__mpm_max_connections_per_child | quote }}
|
||||
|
||||
ExtendedStatus {{ apache__status_extended_enabled | bool | ternary("On", "Off") }}
|
||||
|
||||
|
||||
{% for module_name, value in apache__combined_modules|dictsort %}
|
||||
{% if value is mapping and 'config' in value %}
|
||||
|
||||
<IfModule {{ module_name }}_module>
|
||||
{{ value.config | indent(4) }}
|
||||
</IfModule>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
ServerTokens {{ apache__server_tokens }}
|
||||
ServerSignature {{ apache__server_signature }}
|
||||
TraceEnable {{ apache__trace_enabled }}
|
||||
LogLevel {{ apache__log_level }}
|
||||
|
||||
{{ get_common_headers(item) | indent(4) }}
|
||||
|
||||
{# Don’t use apache__combined_modules because of heavy use of template macros. #}
|
||||
<IfModule ssl_module>
|
||||
{{ get_default_tls_directives(item.value | d({})) }}
|
||||
|
||||
{% if get_openssl_version() is version_compare("0.9.8h", ">=") %}
|
||||
SSLStaplingCache {{ apache__ocsp_stapling_cache | quote }}
|
||||
SSLStaplingResponseMaxAge {{ apache__ocsp_stapling_response_max_age | string }}
|
||||
{% if apache__ocsp_stapling_force_url %}
|
||||
SSLStaplingForceURL {{ apache__ocsp_stapling_force_url | quote }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</IfModule>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if apache__security_module_server_signature != omit %}
|
||||
SecServerSignature "{{ apache__security_module_server_signature }}"
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
{% if item.value.raw | d() %}
|
||||
|
||||
{{ item.value.raw }}
|
||||
{%- endif %}
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
# vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
{% macro get_yaml_list_for_elem(list_or_elem) %}{# [[[ #}
|
||||
{{ ([ list_or_elem ]
|
||||
if (list_or_elem is string or list_or_elem in [True, False])
|
||||
else (list_or_elem | list)) | to_nice_yaml }}
|
||||
{% endmacro %}
|
||||
{% macro get_realm_yaml_list(domains, fallback_realm) %}{# [[[ #}
|
||||
{% set custom_realm_list = [] %}
|
||||
{% if domains and (ansible_local.pki.known_realms | d()) %}
|
||||
{% for domain in (get_yaml_list_for_elem(domains) | from_yaml) %}
|
||||
{% if domain in ansible_local.pki.known_realms %}
|
||||
{% set _ = custom_realm_list.append(domain) %}
|
||||
{% elif (domain.split('.')[1:] | join('.')) in ansible_local.pki.known_realms %}
|
||||
{% set _ = custom_realm_list.append(domain.split('.')[1:] | join('.')) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if custom_realm_list | length == 0 %}
|
||||
{% set _ = custom_realm_list.append(fallback_realm) %}
|
||||
{% endif %}
|
||||
{{ custom_realm_list | to_nice_yaml }}
|
||||
{% endmacro %}
|
||||
{% macro get_apache_version() %}{# [[[ #}
|
||||
{{ ansible_local.apache.version | d("2.4.0") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_apache_min_version() %}{# [[[ #}
|
||||
{{ ansible_local.apache.min_version | d("2.4.0") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_openssl_version() %}{# [[[ #}
|
||||
{{ ansible_local.pki.openssl_version | d("1.0.2") }}
|
||||
{% endmacro %}
|
||||
{% macro get_gnutls_version() %}{# [[[ #}
|
||||
{{ ansible_local.pki.gnutls_version | d("0.0.0") }}
|
||||
{% endmacro %}
|
||||
{% macro debops_indent(content, width=4, indentfirst=False) %}{# [[[ #}
|
||||
{# Fixed version of the `indent` filter which does not insert trailing spaces on empty lines.
|
||||
## Note that you can not use this macro like a filter but have to use it like a regular macro.
|
||||
## Example: {{ indent(some_content, 4) }}
|
||||
##
|
||||
## Python re.sub seems to default to re.MULTILINE in Ansible.
|
||||
#}
|
||||
{{ content | indent(width, indentfirst) | regex_replace("[ \\t\\r\\f\\v]+(\\n|$)", "\\1") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_min_version_wrapped(content, version, compare_operator) %}{# [[[ #}
|
||||
{# Examples:
|
||||
|
||||
{{ get_min_version_wrapped('# 2.3.0 directive', "2.3", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.4.0 directive', "2.4", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.4.1 directive', "2.4.1", ">=") }}
|
||||
{{ get_min_version_wrapped('# 2.5.0 directive', "2.5", ">=") }}
|
||||
|
||||
#}
|
||||
{% set version = '==' if (version == '=') else version %}
|
||||
{% set apache__tpl_compare_operator_includes_equal = True if (compare_operator in ['>=', '<=', '==']) else False %}
|
||||
{% if (version is version_compare(get_apache_min_version(), compare_operator))
|
||||
or (version is version_compare(get_apache_min_version(), ">")) %}
|
||||
{% if apache__tpl_compare_operator_includes_equal and (version is version_compare(get_apache_min_version(), "==")) %}
|
||||
{{ content -}}
|
||||
{% else %}
|
||||
<IfVersion {{ compare_operator }} {{ version }}>
|
||||
{{ debops_indent(content, 4) }}
|
||||
</IfVersion>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_version_wrapped(content, version, compare_operator, fallback_content=False) %}{# [[[ #}
|
||||
{# This macro has not been extensively tested yet. If it contains bugs please try to debug it if you need it.
|
||||
|
||||
Examples:
|
||||
|
||||
{{ get_version_wrapped('# 2.3.0 directive', "2.3", ">=", '# Prior to 2.3 directive') }}
|
||||
{{ get_version_wrapped('# 2.4.0 directive', "2.4", ">=", '# Prior to 2.4 directive') }}
|
||||
{{ get_version_wrapped('# 2.4.1 directive', "2.4.1", ">=", '# Prior to 2.4.1 directive') }}
|
||||
{{ get_version_wrapped('# 2.5.0 directive', "2.5", ">=", '# Prior to 2.5 directive') }}
|
||||
|
||||
#}
|
||||
{% set version = '==' if (version == '=') else version %}
|
||||
{% set apache__tpl_xor_compare_operator_map = {} %}
|
||||
{% set apache__tpl_xor_compare_operator_list = [
|
||||
('==', '!='),
|
||||
('>=', '<'),
|
||||
('<=', '>'),
|
||||
] %}
|
||||
{% for compare_operator, xor_compare_operator in apache__tpl_xor_compare_operator_list %}
|
||||
{% set _ = apache__tpl_xor_compare_operator_map.update({ compare_operator: xor_compare_operator }) %}
|
||||
{% set _ = apache__tpl_xor_compare_operator_map.update({ xor_compare_operator: compare_operator }) %}
|
||||
{% endfor %}
|
||||
{% if apache__config_use_if_version | bool %}
|
||||
{{ get_min_version_wrapped(content, version, compare_operator) -}}
|
||||
{% if fallback_content != False %}
|
||||
{{ get_min_version_wrapped(fallback_content, version, apache__tpl_xor_compare_operator_map[compare_operator]) -}}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if get_apache_version() is version_compare(version, compare_operator) %}
|
||||
{{ content -}}
|
||||
{% elif fallback_content != False %}
|
||||
{{ fallback_content -}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_server_name_aliases(name_item) %}{# [[[ #}
|
||||
{% set apache__tpl_names = get_yaml_list_for_elem(name_item) | from_yaml %}
|
||||
{% if not apache__tpl_names %}
|
||||
{% set apache__tpl_names = [ apache__server_name ] %}
|
||||
{% endif %}
|
||||
ServerName {{ apache__tpl_names[0] | quote }}
|
||||
{% if apache__tpl_names | length > 1 %}
|
||||
ServerAlias {{ apache__tpl_names[1:] | map("quote") | join(" ") }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_listen_sockets(item_listen_list, server_port_listen_list) %}{# [[[ #}
|
||||
{% set apache__tpl_listen_sockets = [] %}
|
||||
{% if item_listen_list | length == 0 %}
|
||||
{% set item_listen_list = server_port_listen_list %}
|
||||
{% endif %}
|
||||
{% for item_listen in item_listen_list %}
|
||||
{% if ':' not in item_listen | string %}
|
||||
{# {% if item_listen in server_port_listen_list %}
|
||||
## Apparently, this is not even needed for Apache to (re)start without issues. #}
|
||||
{% set _ = apache__tpl_listen_sockets.append("*:" + item_listen | string) %}
|
||||
{% else %}
|
||||
{% set _ = apache__tpl_listen_sockets.append(item_listen | string) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ apache__tpl_listen_sockets | join(" ") -}}
|
||||
{% endmacro %}
|
||||
{% macro get_header_comments(item) %}{# [[[ #}
|
||||
{% if item.by_role | d() %}
|
||||
|
||||
# Generated by Ansible role: {{ item.by_role }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_server_directives(item) %}{# [[[ #}
|
||||
{% set sanitized_name = (get_yaml_list_for_elem(item.filename | d(item.name)) | from_yaml)[0] | replace(".", "_") %}
|
||||
{% if item.name | d([]) %}
|
||||
{{ get_server_name_aliases(item.name | d([])) }}
|
||||
{% endif %}
|
||||
ServerAdmin {{ item.server_admin | d(apache__server_admin) | quote }}
|
||||
CustomLog {{ item.custom_log | d('${APACHE_LOG_DIR}/' + sanitized_name + '_access.log' + ' ' + apache__access_log_format + ' ' + item.custom_log_condition | d()) }}
|
||||
ErrorLog {{ item.error_log | d('${APACHE_LOG_DIR}/' + sanitized_name + '_error.log') }}
|
||||
{% endmacro %}
|
||||
{% macro get_server_status_directives(item, enabled) %}{# [[[ #}
|
||||
{% if enabled | bool %}
|
||||
<Location {{ item.status_location | d(apache__status_location) | quote }}>
|
||||
SetHandler server-status
|
||||
{% if item.status_allow_localhost | d(apache__status_allow_localhost) | bool %}
|
||||
Require local
|
||||
{% endif %}
|
||||
{% if item.status_directives | d(apache__status_directives) %}
|
||||
{{ item.status_directives | d(apache__status_directives) }}
|
||||
{% elif not (item.status_allow_localhost | d(apache__status_allow_localhost) | bool) %}
|
||||
Require all denied
|
||||
{% endif %}
|
||||
</Location>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_vhost_content_directives(item, mode='https', https_enabled=True) %}{# [[[ #}
|
||||
{% set apache__tpl_use_redirect_module = 'alias' %}
|
||||
{% set apache__tpl_status_enabled = item.status_enabled | d(apache__status_for_vhost_enabled) | bool %}
|
||||
{{ get_server_status_directives(item, apache__tpl_status_enabled) -}}
|
||||
{% if apache__tpl_status_enabled | bool and (
|
||||
(mode == 'http' and (item.redirect_http | d() or item.redirect_to_https | d(apache__redirect_to_https) | bool)) or
|
||||
(mode == 'https' and item.redirect_https | d())
|
||||
) %}
|
||||
<IfModule mod_rewrite>
|
||||
RewriteEngine On
|
||||
RewriteRule "^{{ item.status_location | d(apache__status_location) }}" "-" [L]
|
||||
</IfModule>
|
||||
{% set apache__tpl_use_redirect_module = 'rewrite' %}
|
||||
{% endif %}
|
||||
{% if mode == 'http' and item.redirect_http | d() %}
|
||||
{{ get_redirect(item.redirect_http_code | d(307), "/", item.redirect_http, apache__tpl_use_redirect_module) }}
|
||||
{% elif mode == 'http' and item.redirect_to_https | d(apache__redirect_to_https) | bool %}
|
||||
{{ get_redirect(item.redirect_to_https_with_code | d("301"), "/", "https://" + (get_yaml_list_for_elem(item.name) | from_yaml)[0], apache__tpl_use_redirect_module) }}
|
||||
{% elif mode == 'https' and item.redirect_https | d() %}
|
||||
{{ get_redirect(item.redirect_https_code | d(307), "/", item.redirect_https, apache__tpl_use_redirect_module) }}
|
||||
{% else %}
|
||||
{{ get_content_directives(item) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_document_root_directives(item) %}{# [[[ #}
|
||||
Options {{ get_yaml_list_for_elem(item.options | d(apache__vhost_options)) | from_yaml | join(" ") }}
|
||||
AllowOverride {{ get_yaml_list_for_elem(item.allow_override | d(apache__vhost_allow_override)) | from_yaml | join(" ") }}
|
||||
|
||||
{{ get_version_wrapped('Require all granted', "2.4", ">=",
|
||||
'Order allow,deny
|
||||
Allow from all') -}}
|
||||
{% if item.root_directives | d() %}
|
||||
|
||||
{{ item.root_directives }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_content_directives(item) %}{# [[[ #}
|
||||
{% if item.include | d() %}
|
||||
{% for include_file in get_yaml_list_for_elem(item.include) | from_yaml %}
|
||||
Include {{ include_file | quote }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if item.include_optional | d() %}
|
||||
{% for include_optional_file in get_yaml_list_for_elem(item.include_optional) | from_yaml %}
|
||||
IncludeOptional {{ include_optional_file | quote }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if item.root | d(item.document_root | d()) %}
|
||||
DocumentRoot {{ item.root | d(item.document_root) | quote }}
|
||||
|
||||
{% if item.index | d() %}
|
||||
DirectoryIndex {{ get_yaml_list_for_elem(item.index) | from_yaml | join(" ") }}
|
||||
{% endif %}
|
||||
{% if item.alias | d() %}
|
||||
{{ get_alias(item.alias, item.alias_path | d(item.root) | d(item.document_root)) }}
|
||||
{%- endif %}
|
||||
<Directory {{ item.root | d(item.document_root) | quote }}>
|
||||
{{ debops_indent(get_document_root_directives(item), 4) }}
|
||||
</Directory>
|
||||
{% endif %}
|
||||
{% if item.raw_content | d() %}
|
||||
|
||||
{{ item.raw_content }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_default_tls_directives(item) %}{# [[[ #}
|
||||
{# Included in server context to provide sane defaults (there might be vhosts
|
||||
# not controlled by this template) and in virtual host context to ensure those
|
||||
# settings are appliend and to allow per-vhost changes.
|
||||
# Refer to Applied-Crypto-Hardening_bettercrypto/src/configuration/Webservers/Apache/default-ssl for details.
|
||||
#}
|
||||
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||
SSLOptions +StdEnvVars
|
||||
</FilesMatch>
|
||||
<Directory /usr/lib/cgi-bin>
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
|
||||
BrowserMatch "MSIE [2-6]" \
|
||||
nokeepalive ssl-unclean-shutdown \
|
||||
downgrade-1.0 force-response-1.0
|
||||
# MSIE 7 and newer should be able to use keepalive
|
||||
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||
|
||||
# TLS cipher suites set: {{ item.tls_cipher_suite_set_name | d(apache__tls_cipher_suite_set_name) | quote }}
|
||||
SSLCipherSuite {{ apache__tls_cipher_suite_sets[item.tls_cipher_suite_set_name | d(apache__tls_cipher_suite_set_name)] | quote }}
|
||||
SSLProtocol {{ item.tls_protocols | d(apache__tls_protocols) | join(" ") }}
|
||||
SSLHonorCipherOrder {{ item.tls_honor_cipher_order | d(apache__tls_honor_cipher_order) | quote }}
|
||||
SSLCompression {{ item.tls_compression | d(apache__tls_compression) | quote }}
|
||||
|
||||
{#
|
||||
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html
|
||||
# https://github.com/sovereign/sovereign/issues/373
|
||||
#}
|
||||
{% if get_apache_version() is version_compare("2.4.8", ">=") and get_openssl_version() is version_compare("1.0.2", ">=") %}
|
||||
# SSLOpenSSLConfCmd DHParameters {{ item.tls_dhparam_file | d(apache__tls_dhparam_file) | quote }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_https_directives(item) %}{# [[[ #}
|
||||
SSLEngine on
|
||||
|
||||
{{ get_default_tls_directives(item) }}
|
||||
{% set apache__tpl_pki_realm = item.pki_realm | d((get_realm_yaml_list(item.name, apache__pki_realm) | from_yaml)[0]) %}
|
||||
{% set apache__tpl_pki_realm_path = apache__pki_realm_path + "/" + apache__tpl_pki_realm %}
|
||||
SSLCertificateFile {{ item.tls_crt | d(apache__tpl_pki_realm_path + "/" + (item.pki_crt | d(apache__pki_crt_filename))) | quote }}
|
||||
SSLCertificateKeyFile {{ item.tls_key | d(apache__tpl_pki_realm_path + "/" + (item.pki_key | d(apache__pki_key_filename))) | quote }}
|
||||
{% if item.ocsp_stapling_enabled | d(apache__ocsp_stapling_enabled) | bool and get_openssl_version() is version_compare("0.9.8h", ">=") %}
|
||||
SSLUseStapling on
|
||||
{% endif %}
|
||||
|
||||
{% if item.hsts_enabled | d(apache__hsts_enabled) | bool %}
|
||||
Header always set Strict-Transport-Security "max-age={{ item.hsts_max_age | d(apache__hsts_max_age) }}{{ "; includeSubDomains" if item.hsts_subdomains | d(apache__hsts_subdomains) | bool else "" }}{{ "; preload" if ((item.hsts_preload | d(apache__hsts_preload)) | bool) else "" }}"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_http_security_headers(item) %}{# [[[ #}
|
||||
{% set apache__tpl_directive_options = get_yaml_list_for_elem(item.http_sec_headers_directive_options | d(apache__http_sec_headers_directive_options)) | from_yaml | map("quote") | join(" ") %}
|
||||
{% if item.csp_enabled | d(False) | bool %}
|
||||
Header {{ apache__tpl_directive_options }} Content-Security-Policy "{{ item.csp | d("default-src https: ;") + (" " + item.csp_append | d(apache__http_csp_append) if (item.csp_append | d(apache__http_csp_append)) else "") }}"
|
||||
{% endif %}
|
||||
{% if item.csp_report_enabled | d(False) | bool %}
|
||||
Header {{ apache__tpl_directive_options }} Content-Security-Policy-Report-Only "{{ item.csp_report | d(item.csp | d("default-src https: ;")) + (" " + item.csp_append | d(apache__http_csp_append) if (item.csp_append | d(apache__http_csp_append)) else "") }}"
|
||||
{% endif %}
|
||||
{% if item.http_frame_options | d(apache__http_frame_options) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-Frame-Options "{{ item.http_frame_options | d(apache__http_frame_options) }}"
|
||||
{% endif %}
|
||||
{% if item.http_xss_protection | d(apache__http_xss_protection) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-XSS-Protection "{{ item.http_xss_protection | d(apache__http_xss_protection) }}"
|
||||
{% endif %}
|
||||
{% if item.http_referrer_policy | d(apache__http_referrer_policy) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} Referrer-Policy "{{ item.http_referrer_policy | d(apache__http_referrer_policy) }}"
|
||||
{% endif %}
|
||||
{% if item.http_content_type_options | d(apache__http_content_type_options) != omit %}
|
||||
Header {{ apache__tpl_directive_options }} X-Content-Type-Options "{{ item.http_content_type_options | d(apache__http_content_type_options) }}"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_common_headers(item) %}{# [[[ #}
|
||||
{% if item.http_clacks_overhead | d(apache__http_clacks_overhead | d(True)) | bool %}
|
||||
{#
|
||||
# Respect the will of the DebOps Creator.
|
||||
# Ref: https://github.com/debops/ansible-nginx/commit/d6cd455c68a7584b2592053fd98d3e539054e09a
|
||||
#}
|
||||
Header always set X-Clacks-Overhead "GNU Terry Pratchett"
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_redirect(code, from, to, module) %}{# [[[ #}
|
||||
{# Prefer the alias module but support the use of the rewrite module in case
|
||||
other rewrite rules are used in the same context because the rewrite rules are
|
||||
handled before all the directives from the alias module.
|
||||
#}
|
||||
{% set to = to + ("/" if (to[-1] != "/") else "") %}
|
||||
{% if module == 'alias' %}
|
||||
Redirect {{ code | string }} "{{ from }}" "{{ to }}"
|
||||
{% elif module == 'rewrite' %}
|
||||
<IfModule mod_rewrite>
|
||||
RewriteRule "^{{ from }}?(.*)" "{{ to }}$1" [L,R={{ code }},NE]
|
||||
</IfModule>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro get_alias(url_path, fs_directory) %}{# [[[ #}
|
||||
Alias {{ url_path | quote }} {{ (fs_directory + ("/" if (fs_directory[-1] != "/") else "")) | quote }}
|
||||
{% endmacro %}
|
||||
{% set apache__tpl_vhost_http_enabled = True if (get_listen_sockets(item.listen_http | d([]), apache__http_listen)) else False %}
|
||||
{% set apache__tpl_vhost_https_enabled = True if (item.https_enabled | d(apache__https_enabled) | bool and get_listen_sockets(item.listen_https | d([]), apache__https_listen)) else False %}
|
||||
{{ get_header_comments(item) }}
|
||||
|
||||
{% if apache__tpl_vhost_http_enabled | bool %}
|
||||
# Virtual host handling HTTP [[[
|
||||
<VirtualHost {{ get_listen_sockets(item.listen_http | d([]), apache__http_listen) }}>
|
||||
|
||||
{{ debops_indent(get_server_directives(item), 4) }}
|
||||
|
||||
{{ debops_indent(get_vhost_content_directives(item, mode='http', https_enabled=apache__tpl_vhost_https_enabled), 4) }}
|
||||
|
||||
</VirtualHost>
|
||||
# ]]]
|
||||
{% endif %}
|
||||
|
||||
{% if apache__tpl_vhost_https_enabled | bool %}
|
||||
# Virtual host handling HTTPS [[[
|
||||
<IfModule ssl_module>
|
||||
<VirtualHost {{ get_listen_sockets(item.listen_https | d([]), apache__https_listen) }}>
|
||||
|
||||
{{ debops_indent(get_server_directives(item), 4) }}
|
||||
|
||||
{{ debops_indent(get_https_directives(item), 4) }}
|
||||
{{ debops_indent(get_http_security_headers(item), 4) }}
|
||||
{{ debops_indent(get_common_headers(item), 4) }}
|
||||
|
||||
{{ debops_indent(get_vhost_content_directives(item, mode='https'), 4) }}
|
||||
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
# ]]]
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
{% if item.raw | d() %}
|
||||
|
||||
{{ item.raw }}
|
||||
{%- endif %}
|
||||
20
ansible_collections/debops/debops/roles/apparmor/COPYRIGHT
Normal file
20
ansible_collections/debops/debops/roles/apparmor/COPYRIGHT
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
apparmor - Install and configure AppArmor
|
||||
|
||||
Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
Copyright (C) 2015-2022 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# .. Copyright (C) 2015-2022 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apparmor__ref_defaults:
|
||||
|
||||
# Default variables
|
||||
# =================
|
||||
#
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# Packages and installation [[[
|
||||
# -----------------------------
|
||||
|
||||
# .. envvar:: apparmor__base_packages [[[
|
||||
#
|
||||
# List of base packages to install.
|
||||
apparmor__base_packages:
|
||||
- 'apparmor'
|
||||
- 'apparmor-utils'
|
||||
- 'apparmor-profiles'
|
||||
- 'apparmor-profiles-extra'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__packages [[[
|
||||
#
|
||||
# List of additional packages to install.
|
||||
apparmor__packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__enabled [[[
|
||||
#
|
||||
# Enable or disable support the AppArmor. Since the role is included from the
|
||||
# DebOps ``common`` playbook, this allows a manual override of the default
|
||||
# behavior.
|
||||
apparmor__enabled: '{{ ansible_local.apparmor.enabled
|
||||
| d(False
|
||||
if (ansible_distribution_release in ["stretch"] or
|
||||
(ansible_virtualization_role | d("") == "guest"
|
||||
and
|
||||
ansible_virtualization_type | d("") in
|
||||
["container"]))
|
||||
else True) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__manage_grub [[[
|
||||
#
|
||||
# Enable or disable support for adding kernel parameters via GRUB which cause
|
||||
# the AppArmor security module to be enabled at boot. Note that the normal
|
||||
# Debian/Ubuntu kernel packages already include and enable this support by
|
||||
# default, so this is only necessary for old distributions and/or customized
|
||||
# kernel builds.
|
||||
apparmor__manage_grub: '{{ ansible_local.apparmor.grub_enabled
|
||||
| d(True
|
||||
if (apparmor__enabled | d(False) | bool and
|
||||
ansible_distribution_release in ["stretch"])
|
||||
else False) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__kernel_parameters [[[
|
||||
#
|
||||
# Kernel parameters needed to enable AppArmor (if not already enabled by
|
||||
# default, as in recent Debian/Ubuntu kernel packages). Only relevant if
|
||||
# :envvar:`apparmor__manage_grub` is enabled.
|
||||
apparmor__kernel_parameters:
|
||||
- 'apparmor=1'
|
||||
- 'security=apparmor'
|
||||
|
||||
# ]]]
|
||||
# ]]]
|
||||
# AppArmor profiles [[[
|
||||
# ---------------------
|
||||
|
||||
# These variables control the state of individual AppArmor profiles. See
|
||||
# :ref:`apparmor__ref_profiles` for more details.
|
||||
|
||||
# .. envvar:: apparmor__default_profiles [[[
|
||||
#
|
||||
# List of profiles to enable/disable, defined by the role.
|
||||
apparmor__default_profiles: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__profiles [[[
|
||||
#
|
||||
# List of profiles to enable/disable, defined for all hosts in the Ansible
|
||||
# inventory.
|
||||
apparmor__profiles: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__group_profiles [[[
|
||||
#
|
||||
# List of profiles to enable/disable, defined on hosts in a specific Ansible
|
||||
# inventory group.
|
||||
apparmor__group_profiles: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__host_profiles [[[
|
||||
#
|
||||
# List of profiles to enable/disable, defined on specific hosts in the Ansible
|
||||
# inventory.
|
||||
apparmor__host_profiles: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__dependent_profiles [[[
|
||||
#
|
||||
# Variable definitions managed by roles using this role as dependency.
|
||||
apparmor__dependent_profiles: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__combined_profiles [[[
|
||||
#
|
||||
# A combination of the profiles to enable/disable, defined by the other
|
||||
# variables, used in role tasks.
|
||||
apparmor__combined_profiles: '{{ apparmor__default_profiles
|
||||
+ apparmor__profiles
|
||||
+ apparmor__group_profiles
|
||||
+ apparmor__host_profiles
|
||||
+ apparmor__dependent_profiles }}'
|
||||
|
||||
# ]]]
|
||||
# ]]]
|
||||
# AppArmor local profile modifications [[[
|
||||
# ----------------------------------------
|
||||
|
||||
# These variables control local profile modifications. See
|
||||
# :ref:`apparmor__ref_locals` for more details.
|
||||
|
||||
# .. envvar:: apparmor__default_locals [[[
|
||||
#
|
||||
# List of default local profile modifications defined by the role.
|
||||
apparmor__default_locals: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__locals [[[
|
||||
#
|
||||
# List of local profile modifications defined for all hosts in the Ansible
|
||||
# inventory.
|
||||
apparmor__locals: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__group_locals [[[
|
||||
#
|
||||
# List of local profile modifications defined on hosts in a specific Ansible
|
||||
# inventory group.
|
||||
apparmor__group_locals: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__host_locals [[[
|
||||
#
|
||||
# List of local profile modifications defined on specific hosts in the Ansible
|
||||
# inventory.
|
||||
apparmor__host_locals: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__dependent_locals [[[
|
||||
#
|
||||
# Variable definitions managed by roles using this role as dependency.
|
||||
apparmor__dependent_locals: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__combined_locals [[[
|
||||
#
|
||||
# A combination of the local profile modifications defined by the other
|
||||
# variables, used in role tasks.
|
||||
apparmor__combined_locals: '{{ apparmor__default_locals
|
||||
+ apparmor__locals
|
||||
+ apparmor__group_locals
|
||||
+ apparmor__host_locals
|
||||
+ apparmor__dependent_locals }}'
|
||||
|
||||
# ]]]
|
||||
# ]]]
|
||||
# AppArmor tunables [[[
|
||||
# ---------------------
|
||||
|
||||
# These variables control profile tunables. See :ref:`apparmor__ref_tunables`
|
||||
# for more details.
|
||||
|
||||
# .. envvar:: apparmor__default_tunables [[[
|
||||
#
|
||||
# List of default tunables defined by the role.
|
||||
apparmor__default_tunables: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__tunables [[[
|
||||
#
|
||||
# List of tunables defined for all hosts in the Ansible inventory.
|
||||
apparmor__tunables: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__group_tunables [[[
|
||||
#
|
||||
# List of tunables defined on hosts in a specific Ansible inventory group.
|
||||
apparmor__group_tunables: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__host_tunables [[[
|
||||
#
|
||||
# List of tunables defined on specific hosts in the Ansible inventory.
|
||||
apparmor__host_tunables: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__dependent_tunables [[[
|
||||
#
|
||||
# Variable definitions managed by roles using this role as dependency.
|
||||
apparmor__dependent_tunables: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apparmor__combined_tunables [[[
|
||||
#
|
||||
# A combination of the tunables defined by the other variables, used in
|
||||
# role tasks.
|
||||
apparmor__combined_tunables: '{{ apparmor__default_tunables
|
||||
+ apparmor__tunables
|
||||
+ apparmor__group_tunables
|
||||
+ apparmor__host_tunables
|
||||
+ apparmor__dependent_tunables }}'
|
||||
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2015-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Robin Schneider'
|
||||
description: 'Install and configure AppArmor'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.1.3'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- security
|
||||
- hardening
|
||||
- mac
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Create base directory for local modification {{ item.name }}
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apparmor.d/local/" + item.name | dirname }}'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
when:
|
||||
- item.state | d("present") == "present"
|
||||
- item.name | dirname != ""
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
||||
- name: Create local modification {{ item.name }}
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apparmor.d/snippet.j2'
|
||||
dest: '{{ "/etc/apparmor.d/local/" + item.name }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
when: item.state | d("present") == "present"
|
||||
vars:
|
||||
apparmor__var_template_title: 'AppArmor local modification'
|
||||
apparmor__var_template_suffix: ','
|
||||
apparmor__var_template_operator: ' '
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
||||
- name: Check the presence of profile {{ item.name }}
|
||||
ansible.builtin.stat:
|
||||
path: '{{ "/etc/apparmor.d/" + item.name }}'
|
||||
register: apparmor__register_local_profile
|
||||
when: item.state | d("present") == "absent"
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
||||
- name: Truncate local modification {{ item.name }}
|
||||
ansible.builtin.copy:
|
||||
dest: '{{ "/etc/apparmor.d/local/" + item.name }}'
|
||||
content: ''
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
when:
|
||||
- item.state | d("present") == "absent"
|
||||
- apparmor__register_local_profile.stat.exists | d(False)
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
||||
- name: Remove local modification {{ item.name }}
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apparmor.d/local/" + item.name }}'
|
||||
state: 'absent'
|
||||
when:
|
||||
- item.state | d("present") == "absent"
|
||||
- not apparmor__register_local_profile.stat.exists | d(False)
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Ensure a valid state for profile {{ item.name }}
|
||||
ansible.builtin.assert:
|
||||
that: item.state | d() in [ "enforce", "complain", "disable", "ignore" ]
|
||||
quiet: True
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
||||
- name: Check presence of profile {{ item.name }}
|
||||
ansible.builtin.stat:
|
||||
path: '{{ "/etc/apparmor.d/" + item.name }}'
|
||||
register: apparmor__stat_profile
|
||||
when: item.state != "ignore"
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
||||
# Note: the aa-* utils happily exit with 0 even when the profile doesn't exist
|
||||
- name: Ensure existence of profile {{ item.name }}
|
||||
ansible.builtin.assert:
|
||||
that: apparmor__stat_profile.stat.exists | d(False)
|
||||
quiet: True
|
||||
when: item.state != "ignore"
|
||||
tags: [ 'apparmor:profiles' ]
|
||||
|
||||
- name: Register current AppArmor state
|
||||
ansible.builtin.command: aa-status --json
|
||||
register: apparmor__register_old_status
|
||||
changed_when: False
|
||||
when: item.state != "ignore"
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
||||
# Note: can't use --no-reload here, because aa-status won't show any changes
|
||||
- name: Set profile {{ item.name + " to " + item.state }}
|
||||
ansible.builtin.shell: set -o nounset -o pipefail -o errexit &&
|
||||
aa-{{ item.state }} {{ ("/etc/apparmor.d/" + item.name) | quote }}
|
||||
> /dev/null 2>&1 &&
|
||||
aa-status --json
|
||||
args:
|
||||
executable: bash
|
||||
register: apparmor__register_new_status
|
||||
changed_when: apparmor__register_new_status.stdout != apparmor__register_old_status.stdout
|
||||
when: item.state != "ignore"
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Note: these two could be merged, but it makes the output much more confusing
|
||||
- name: Remove tunable {{ item.name }}
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ "/etc/apparmor.d/tunables/" + item.name }}'
|
||||
state: 'absent'
|
||||
delete: True
|
||||
when: item.state | d("present") == "absent"
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:tunables' ]
|
||||
|
||||
- name: Divert tunable {{ item.name }}
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ "/etc/apparmor.d/tunables/" + item.name }}'
|
||||
state: 'present'
|
||||
delete: True
|
||||
when: item.state | d("present") == "present"
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:tunables' ]
|
||||
|
||||
- name: Create base directory for tunable {{ item.name }}
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apparmor.d/tunables/" + item.name | dirname }}'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
when:
|
||||
- item.state | d("present") == "present"
|
||||
- item.name | dirname != ""
|
||||
tags: [ 'role::apparmor:tunables' ]
|
||||
|
||||
- name: Create tunable {{ item.name }}
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apparmor.d/snippet.j2'
|
||||
dest: '{{ "/etc/apparmor.d/tunables/" + item.name }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
vars:
|
||||
apparmor__var_template_title: 'AppArmor tunable'
|
||||
apparmor__var_template_suffix: ''
|
||||
apparmor__var_template_operator: '='
|
||||
when: item.state | d("present") == "present"
|
||||
notify: [ 'Reload all AppArmor profiles' ]
|
||||
tags: [ 'role::apparmor:tunables' ]
|
||||
127
ansible_collections/debops/debops/roles/apparmor/tasks/main.yml
Normal file
127
ansible_collections/debops/debops/roles/apparmor/tasks/main.yml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2015-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import custom Ansible plugins
|
||||
ansible.builtin.import_role:
|
||||
name: 'ansible_plugins'
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", (apparmor__base_packages
|
||||
+ apparmor__packages)) }}'
|
||||
state: 'present'
|
||||
register: apparmor__register_packages
|
||||
until: apparmor__register_packages is succeeded
|
||||
tags: [ 'role::apparmor:pkg' ]
|
||||
|
||||
- name: Make sure that the Ansible local facts directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Save AppArmor local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apparmor.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apparmor.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Update Ansible facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
||||
- name: Add AppArmor kernel parameters to GRUB configuration
|
||||
ansible.builtin.template:
|
||||
src: 'etc/default/grub.d/debops.apparmor.cfg.j2'
|
||||
dest: '/etc/default/grub.d/debops.apparmor.cfg'
|
||||
mode: '0644'
|
||||
when: >
|
||||
apparmor__enabled | d(False) | bool and
|
||||
apparmor__manage_grub | d(False) | bool
|
||||
notify: [ 'Update GRUB' ]
|
||||
tags: [ 'role::apparmor:grub' ]
|
||||
|
||||
- name: Remove AppArmor kernel parameters from GRUB configuration
|
||||
ansible.builtin.file:
|
||||
path: '/etc/default/grub.d/debops.apparmor.cfg'
|
||||
state: 'absent'
|
||||
when: >
|
||||
not apparmor__enabled | d(False) | bool or
|
||||
not apparmor__manage_grub | d(False) | bool
|
||||
notify: [ 'Update GRUB' ]
|
||||
tags: [ 'role::apparmor:grub' ]
|
||||
|
||||
- name: Remove legacy GRUB configuration options
|
||||
ansible.builtin.lineinfile:
|
||||
dest: '/etc/default/grub'
|
||||
regexp: '^GRUB_CMDLINE_LINUX="(.*?)\$GRUB_CMDLINE_LINUX_ANSIBLE_APPARMOR(.*)"'
|
||||
line: 'GRUB_CMDLINE_LINUX="\1 \2"'
|
||||
backrefs: yes
|
||||
mode: '0644'
|
||||
notify: [ 'Update GRUB' ]
|
||||
tags: [ 'role::apparmor:grub' ]
|
||||
|
||||
- name: Configure tunables
|
||||
ansible.builtin.include_tasks: handle_tunables.yml
|
||||
loop: '{{ apparmor__combined_tunables | debops.debops.parse_kv_items() }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
tags: [ 'role::apparmor:tunables' ]
|
||||
|
||||
- name: Configure local changes to system profiles
|
||||
ansible.builtin.include_tasks: handle_locals.yml
|
||||
loop: '{{ apparmor__combined_locals | debops.debops.parse_kv_items() }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
tags: [ 'role::apparmor:locals' ]
|
||||
|
||||
- name: Configure profiles
|
||||
ansible.builtin.include_tasks: handle_profiles.yml
|
||||
loop: '{{ apparmor__combined_profiles | debops.debops.parse_kv_items() }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
||||
- name: Start and enable the AppArmor service
|
||||
ansible.builtin.service:
|
||||
name: 'apparmor'
|
||||
state: 'started'
|
||||
enabled: True
|
||||
when:
|
||||
- apparmor__enabled | d(False) | bool
|
||||
- ansible_local.apparmor.installed | d(False) | bool
|
||||
tags: [ 'role::apparmor:service' ]
|
||||
|
||||
- name: Reload AppArmor profiles if necessary
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
||||
- name: Stop and disable the AppArmor service
|
||||
ansible.builtin.service:
|
||||
name: 'apparmor'
|
||||
state: 'stopped'
|
||||
enabled: False
|
||||
when:
|
||||
- not apparmor__enabled | d(False) | bool
|
||||
- ansible_local.apparmor.installed | d(False) | bool
|
||||
tags: [ 'role::apparmor:service' ]
|
||||
|
||||
- name: Unload all AppArmor profiles
|
||||
ansible.builtin.command: aa-teardown
|
||||
when:
|
||||
- not apparmor__enabled | d(False) | bool
|
||||
- ansible_local.apparmor.installed | d(False) | bool
|
||||
register: apparmor__register_teardown
|
||||
changed_when: apparmor__register_teardown.changed | bool
|
||||
tags: [ 'role::apparmor:profiles' ]
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps, loads
|
||||
import os
|
||||
|
||||
|
||||
def cmd_exists(cmd):
|
||||
return any(
|
||||
os.access(os.path.join(path, cmd), os.X_OK)
|
||||
for path in os.environ["PATH"].split(os.pathsep)
|
||||
)
|
||||
|
||||
|
||||
def read_kernel_bool(path):
|
||||
value = 'N'
|
||||
|
||||
try:
|
||||
with open(path, 'r') as file:
|
||||
value = file.read().strip()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return value.upper() == 'Y'
|
||||
|
||||
|
||||
output = loads('''{{ {
|
||||
"enabled": apparmor__enabled | d(False) | bool,
|
||||
"grub_enabled" apparmor__manage_grub | d(False) | bool
|
||||
} | to_nice_json }}''')
|
||||
|
||||
output.append({'installed': (cmd_exists('aa-status') and
|
||||
cmd_exists('aa-teardown'))})
|
||||
output.append({'kernel_enabled':
|
||||
read_kernel_bool('/sys/module/apparmor/parameters/enabled')})
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
{#
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
#
|
||||
# {{ item.name }} - {{ appamor__var_template_title | d('Configuration snippet') }}
|
||||
|
||||
{% macro print_option(option, commented, loop_first, level) %}
|
||||
{% if option.state | d('present') not in [ 'absent', 'init', 'ignore' ] %}
|
||||
{% set prefix = ("{:^" + level | string + "}").format('') %}
|
||||
{% set comment_prefix = (prefix + "# ") %}
|
||||
{% if commented or option.state | d('present') == 'comment' %}
|
||||
{% set commented = True %}
|
||||
{% set prefix = comment_prefix %}
|
||||
{% endif %}
|
||||
{% if option.separator | d(False) or level == 0 or (option.comment | d() and not loop_first) %}
|
||||
{{ '' }}
|
||||
{% endif %}
|
||||
{% if option.comment | d() %}
|
||||
{{ option.comment | regex_replace('\n$', '') | comment(prefix='', decoration=comment_prefix, postfix='') -}}
|
||||
{% endif %}
|
||||
{% if option.raw | d() and commented %}
|
||||
{{ '{}'.format(option.raw | regex_replace('\n$', '') | comment(prefix='', decoration=comment_prefix, postfix='')) -}}
|
||||
{% elif option.raw | d() and not commented %}
|
||||
{{ '{}{}'.format(prefix, option.raw | regex_replace('\n$', '')) }}
|
||||
{% elif option.options | d() %}
|
||||
{{ '{}{} {{'.format(prefix, option.option | d(option.name) | regex_replace('\n$', '')) }}
|
||||
{% for option in option.options %}
|
||||
{{ print_option(option, commented, loop.first, level + 1) -}}
|
||||
{% endfor %}
|
||||
{{ '{}}}'.format(prefix) }}
|
||||
{% else %}
|
||||
{% if option.operator | d() %}
|
||||
{% set operator = option.operator %}
|
||||
{% elif option.option | d(option.name) == '#include' %}
|
||||
{% set operator = ' ' %}
|
||||
{% else %}
|
||||
{% set operator = apparmor__var_template_operator | d('=') %}
|
||||
{% endif %}
|
||||
{% set suffix = option.suffix | d(apparmor__var_template_suffix | d('')) %}
|
||||
{{ '{}{}{}{}{}'.format(prefix,
|
||||
option.option | d(option.name),
|
||||
operator,
|
||||
option.value | d(""),
|
||||
suffix) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{##}
|
||||
{% for option in item.options %}
|
||||
{{ print_option(option, False, loop.first, 0) -}}
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
GRUB_CMDLINE_LINUX_DEBOPS_APPARMOR="{{ apparmor__kernel_parameters | d([]) | flatten | join(' ') }}"
|
||||
GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEBOPS_APPARMOR"
|
||||
20
ansible_collections/debops/debops/roles/apt/COPYRIGHT
Normal file
20
ansible_collections/debops/debops/roles/apt/COPYRIGHT
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
debops.apt - Manage APT repositories and keys using Ansible
|
||||
|
||||
Copyright (C) 2013-2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2014-2023 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
793
ansible_collections/debops/debops/roles/apt/defaults/main.yml
Normal file
793
ansible_collections/debops/debops/roles/apt/defaults/main.yml
Normal file
|
|
@ -0,0 +1,793 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2013-2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2014-2023 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt__ref_defaults:
|
||||
|
||||
# debops.apt default variables
|
||||
# ============================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# General configuration [[[
|
||||
# -------------------------
|
||||
|
||||
# .. envvar:: apt__enabled [[[
|
||||
#
|
||||
# Enable or disable management of the APT configuration and sources using this
|
||||
# role.
|
||||
apt__enabled: '{{ True if (ansible_pkg_mgr == "apt") else False }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__deploy_state [[[
|
||||
#
|
||||
# Enable (if ``present``) or disable (if ``absent``) management of the
|
||||
# :file:`/etc/apt/sources.list` configuration file by the role.
|
||||
apt__deploy_state: '{{ "present"
|
||||
if (ansible_facts.distribution in ["Debian", "Raspbian", "Ubuntu", "Devuan"])
|
||||
else "absent" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__cache_valid_time [[[
|
||||
#
|
||||
# Update APT cache early in the playbook if it's older than 24h
|
||||
# Set to False to disable update (useful when changing APT mirrors)
|
||||
apt__cache_valid_time: '{{ ansible_local.core.cache_valid_time | d(60 * 60 * 24) }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Packages to install [[[
|
||||
# -----------------------
|
||||
|
||||
# .. envvar:: apt__base_packages [[[
|
||||
#
|
||||
# Default base packages to install for APT support. You can use the
|
||||
# :ref:`debops.apt_install` role to install other packages not related to the
|
||||
# package manager.
|
||||
apt__base_packages:
|
||||
- 'lsb-release'
|
||||
- 'ca-certificates'
|
||||
- '{{ "apt-transport-https"
|
||||
if (ansible_distribution_release in
|
||||
["stretch", "trusty", "xenial"])
|
||||
else [] }}'
|
||||
- 'gnupg'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__packages [[[
|
||||
#
|
||||
# List of additional APT packages to install for APT support. You can use the
|
||||
# :ref:`debops.apt_install` role to install other packages not related to the
|
||||
# package manager.
|
||||
apt__packages: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# The :file:`/etc/apt/sources.list` defaults [[[
|
||||
# ----------------------------------------------
|
||||
|
||||
# These variables are used in configuration options of the
|
||||
# :file:`/etc/apt/sources.list` configuration file. They are exposed here for
|
||||
# convenience.
|
||||
|
||||
# .. envvar:: apt__archive_types [[[
|
||||
#
|
||||
# List of source types to configure for the default package sources. Supported
|
||||
# choices: ``deb``, ``deb-src``.
|
||||
apt__archive_types: [ 'deb', 'deb-src' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__archive_sources_disabled [[[
|
||||
#
|
||||
# If enabled, the 'deb-src' APT archive sources will be commented out by
|
||||
# default to make APT updates faster.
|
||||
apt__archive_sources_disabled: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__architecture [[[
|
||||
#
|
||||
# The default system architecture present on the host.
|
||||
apt__architecture: '{{ apt__architecture_map[ansible_facts.architecture]
|
||||
| d(ansible_facts.architecture) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__architecture_map [[[
|
||||
#
|
||||
# A YAML dictionary which defines a mapping between Ansible architectures and
|
||||
# Debian/Ubuntu ports. Only definitions that are different from the detected
|
||||
# ones are listed here, otherwise the value of ``ansible_architecture`` is
|
||||
# used.
|
||||
apt__architecture_map:
|
||||
'x86_64': 'amd64'
|
||||
'armv7l': 'armhf'
|
||||
'aarch64': 'arm64'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__distribution [[[
|
||||
#
|
||||
# The Linux distribution present on the host.
|
||||
# Note: this deliberately does not default to ansible_local.core.distribution
|
||||
# because this local fact is set by the 'core' role, which runs later in the
|
||||
# common playbook.
|
||||
# Ref: https://github.com/debops/debops/issues/2046#issuecomment-1086702657
|
||||
apt__distribution: '{{ ansible_facts.lsb.id | d(ansible_facts.distribution) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__distribution_release [[[
|
||||
#
|
||||
# The Linux distribution release present on the host.
|
||||
# Note: this deliberately does not default to
|
||||
# ansible_local.core.distribution_release because this local fact is set by the
|
||||
# 'core' role, which runs later in the common playbook.
|
||||
# Ref: https://github.com/debops/debops/issues/2046#issuecomment-1086702657
|
||||
apt__distribution_release: '{{ ansible_facts.lsb.codename
|
||||
| d(ansible_facts.distribution_release) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__distribution_version [[[
|
||||
#
|
||||
# The OS distribution version, used for specific APT repositories.
|
||||
apt__distribution_version: '{{ ansible_facts.distribution_version }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__nonfree [[[
|
||||
#
|
||||
# Boolean. If enabled, non-free sections of a given distribution repository
|
||||
# will be enabled, otherwise they won't be present.
|
||||
#
|
||||
# By default non-free sections are enabled on hardware-based hosts due to
|
||||
# a possible requirement for non-free firmware packages. The fact script will
|
||||
# also check if non-free section was enabled in the original
|
||||
# :file:`sources.list` file and enable it accordingly.
|
||||
apt__nonfree: '{{ ansible_facts.ansible_local.apt.nonfree
|
||||
| d(True
|
||||
if (ansible_facts.virtualization_role is undefined or
|
||||
ansible_facts.virtualization_role != "guest")
|
||||
else False) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__nonfree_firmware [[[
|
||||
#
|
||||
# Boolean. If enabled, sections of a given distribution repository which
|
||||
# contain non-free firmware packages will be enabled, otherwise they won't be
|
||||
# present.
|
||||
#
|
||||
# By default non-free firmware sections are enabled on hardware-based hosts due
|
||||
# to a possible requirement for non-free firmware packages.
|
||||
apt__nonfree_firmware: '{{ True
|
||||
if (ansible_facts.virtualization_role is undefined or
|
||||
ansible_facts.virtualization_role != "guest")
|
||||
else False }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__distribution_repository_map [[[
|
||||
#
|
||||
# YAML dictionary which maps the distribution OS to its default APT repository.
|
||||
# Values from here are used in multiple entries in the
|
||||
# :file:`/etc/apt/sources.list` configuration and are exposed here for
|
||||
# convenience.
|
||||
apt__distribution_repository_map:
|
||||
'Debian': 'http://deb.debian.org/debian'
|
||||
'Devuan': 'http://deb.devuan.org/merged'
|
||||
'Ubuntu': '{{ "http://archive.ubuntu.com/ubuntu"
|
||||
if (apt__architecture in ["amd64", "i386"])
|
||||
else "http://ports.ubuntu.com/ubuntu-ports" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__debian_archived_releases [[[
|
||||
#
|
||||
# List of Debian releases which have been archived and are not available in the
|
||||
# default APT repositories. This variable is used conditionally to detect if
|
||||
# a given OS release is archived.
|
||||
apt__debian_archived_releases: [ 'wheezy', 'jessie', 'stretch', 'buster' ]
|
||||
# ]]]
|
||||
# ]]]
|
||||
# The :file:`/etc/apt/sources.list` configuration entries [[[
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# .. _apt__ref_sources_defaults:
|
||||
|
||||
# These variables define the contents of the :file:`/etc/apt/sources.list`
|
||||
# configuration file. See :ref:`apt__ref_sources` for more details.
|
||||
|
||||
# .. envvar:: apt__debian_sources [[[
|
||||
#
|
||||
# APT source entries for the Debian distribution.
|
||||
apt__debian_sources:
|
||||
|
||||
- name: 'debian-release'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Debian | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release'
|
||||
uri: 'http://archive.debian.org/debian'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release in apt__debian_archived_releases)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-updates" }}'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release not in apt__debian_archived_releases and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-backports" }}'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release'
|
||||
components: [ 'non-free-firmware' ]
|
||||
state: '{{ "ignore"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release in ["wheezy", "jessie", "stretch",
|
||||
"buster", "bullseye"])
|
||||
else ("present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__nonfree_firmware | bool)
|
||||
else "ignore") }}'
|
||||
|
||||
- name: 'debian-release'
|
||||
components: [ 'contrib', 'non-free' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release-security'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: 'http://deb.debian.org/debian-security/'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-security" }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release not in apt__debian_archived_releases and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release-security'
|
||||
uri: 'http://security.debian.org/'
|
||||
suites:
|
||||
|
||||
# For some reason, filter doesn't accept '' string to reset the list of
|
||||
# suites, so let's reset it "manually" for now.
|
||||
- name: '{{ apt__distribution_release + "-security" }}'
|
||||
state: 'absent'
|
||||
|
||||
- '{{ apt__distribution_release + "/updates" }}'
|
||||
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release not in apt__debian_archived_releases and
|
||||
apt__distribution_release in ["buster"] and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release-security'
|
||||
components: [ 'non-free-firmware' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release not in apt__debian_archived_releases and
|
||||
apt__distribution_release not in ["buster", "bullseye"] and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree_firmware | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'debian-release-security'
|
||||
components: [ 'contrib', 'non-free' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release not in apt__debian_archived_releases and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__devuan_sources [[[
|
||||
#
|
||||
# APT source entries for the Devuan distribution.
|
||||
apt__devuan_sources:
|
||||
|
||||
- name: 'devuan-release'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Devuan | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release'
|
||||
uri: 'http://archive.devuan.org/merged'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__distribution_release in ["jessie", "ascii"])
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-updates" }}'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__distribution_release not in ["jessie", "ascii"] and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-backports" }}'
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__distribution_release not in ["jessie"] and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release'
|
||||
components: [ 'contrib', 'non-free' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release-security'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: 'http://pkgmaster.devuan.org/merged'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-security" }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__distribution_release not in ["jessie", "ascii"] and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'devuan-release-security'
|
||||
components: [ 'contrib', 'non-free' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Devuan" and
|
||||
apt__distribution_release not in ["jessie", "ascii"] and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__ubuntu_sources [[[
|
||||
#
|
||||
# APT source entries for the Ubuntu distribution.
|
||||
apt__ubuntu_sources:
|
||||
|
||||
- name: 'ubuntu-release'
|
||||
comment: |
|
||||
See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
|
||||
newer versions of the distribution.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release'
|
||||
components: [ 'restricted' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-updates'
|
||||
comment: |
|
||||
Major bug fix updates produced after the final release of the
|
||||
distribution.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-updates" }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-updates'
|
||||
components: [ 'restricted' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-universe'
|
||||
comment: |
|
||||
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.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
- '{{ apt__distribution_release + "-updates" }}'
|
||||
components: [ 'universe' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-multiverse'
|
||||
comment: |
|
||||
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
|
||||
your rights to use the software. Also, please note that software in
|
||||
multiverse WILL NOT receive any review or updates from the Ubuntu
|
||||
security team.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
- '{{ apt__distribution_release + "-updates" }}'
|
||||
components: [ 'multiverse' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-backports'
|
||||
comment: |
|
||||
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.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-backports" }}'
|
||||
components: [ 'main' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-backports'
|
||||
components: [ 'restricted' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-backports'
|
||||
components: [ 'universe' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-backports'
|
||||
components: [ 'multiverse' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-partner'
|
||||
comment: |
|
||||
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.
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: 'http://archive.canonical.com/ubuntu'
|
||||
suites:
|
||||
- '{{ apt__distribution_release }}'
|
||||
components: [ 'partner' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-security'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-security" }}'
|
||||
components: [ 'main' ]
|
||||
separate: False
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-security'
|
||||
components: [ 'restricted' ]
|
||||
separate: False
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-universe-security'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-security" }}'
|
||||
components: [ 'universe' ]
|
||||
separate: False
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a")
|
||||
else "ignore" }}'
|
||||
|
||||
- name: 'ubuntu-release-multiverse-security'
|
||||
types: '{{ apt__archive_types }}'
|
||||
uri: '{{ apt__distribution_repository_map.Ubuntu | d() }}'
|
||||
suites:
|
||||
- '{{ apt__distribution_release + "-security" }}'
|
||||
components: [ 'multiverse' ]
|
||||
state: '{{ "present"
|
||||
if (apt__distribution == "Ubuntu" and
|
||||
apt__distribution_version != "n/a" and
|
||||
apt__nonfree | bool)
|
||||
else "ignore" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__sources [[[
|
||||
#
|
||||
# List of APT sources defined on all hosts in the Ansible inventory.
|
||||
apt__sources: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_sources [[[
|
||||
#
|
||||
# List of APT sources defined on hosts in a specific Ansible inventory group.
|
||||
apt__group_sources: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_sources [[[
|
||||
#
|
||||
# List of APT sources defined on specific hosts in the Ansible inventory.
|
||||
apt__host_sources: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__combined_sources [[[
|
||||
#
|
||||
# This variable combines all of the :file:`/etc/apt/sources.list` configuration
|
||||
# lists and is used in role tasks and templates.
|
||||
apt__combined_sources: '{{ apt__debian_sources
|
||||
+ apt__devuan_sources
|
||||
+ apt__ubuntu_sources
|
||||
+ apt__sources
|
||||
+ apt__group_sources
|
||||
+ apt__host_sources }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Extra architectures [[[
|
||||
# -----------------------
|
||||
|
||||
# These lists define extra architectures to be enabled on the host.
|
||||
# The main architecture does not need to be defined that way.
|
||||
|
||||
# .. envvar:: apt__extra_architectures [[[
|
||||
#
|
||||
# List of extra architectures to configure on all hosts in Ansible inventory.
|
||||
apt__extra_architectures: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_extra_architectures [[[
|
||||
#
|
||||
# List of extra architectures to configure on hosts in specific Ansible inventory
|
||||
# group.
|
||||
apt__group_extra_architectures: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_extra_architectures [[[
|
||||
#
|
||||
# List of extra architectures to configure on specific hosts in Ansible inventory.
|
||||
apt__host_extra_architectures: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT packages to purge [[[
|
||||
# -------------------------
|
||||
|
||||
# These lists define what APT packages should be purged (removed along with
|
||||
# their configuration, data files and unused dependencies) from the hosts after
|
||||
# APT repositories have been configured. Since this role is applied in the
|
||||
# bootstrap playbooks, the packages will be purged early on; this might be
|
||||
# useful in certain provisioning setups.
|
||||
#
|
||||
# Use only simple APT package names here. For conditional removal, refer to the
|
||||
# :ref:`debops.apt_install` role.
|
||||
|
||||
# .. envvar:: apt__purge_packages [[[
|
||||
#
|
||||
# List of APT packages to purge on all hosts in the Ansible inventory.
|
||||
apt__purge_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__purge_group_packages [[[
|
||||
#
|
||||
# List of APT packages to purge on hosts in a specific Ansible inventory group.
|
||||
apt__purge_group_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__purge_host_packages [[[
|
||||
#
|
||||
# List of APT packages to purge on specific hosts in the Ansible inventory.
|
||||
apt__purge_host_packages: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT repository keys [[[
|
||||
# -----------------------
|
||||
|
||||
# These lists define APT GPG keys to configure on hosts to enable authenticated
|
||||
# access to additional APT repositories. See :ref:`apt__ref_keys` for more
|
||||
# details.
|
||||
|
||||
# .. envvar:: apt__keys [[[
|
||||
#
|
||||
# List of APT GPG keys to configure on all hosts in Ansible inventory.
|
||||
apt__keys: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_keys [[[
|
||||
#
|
||||
# List of APT GPG keys to configure on hosts in specific Ansible inventory
|
||||
# group.
|
||||
apt__group_keys: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_keys [[[
|
||||
#
|
||||
# List of APT GPG keys to configure on specific hosts in Ansible inventory.
|
||||
apt__host_keys: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT repositories [[[
|
||||
# --------------------
|
||||
|
||||
# These lists define additional APT repositories in the
|
||||
# :file:`/etc/apt/sources.list.d/` directory. See :ref:`apt__ref_repositories` for
|
||||
# more details.
|
||||
|
||||
# .. envvar:: apt__repositories [[[
|
||||
#
|
||||
# List of additional APT repositories for all hosts in Ansible inventory.
|
||||
apt__repositories: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_repositories [[[
|
||||
#
|
||||
# List of additional APT repositories for hosts in specific Ansible inventory
|
||||
# group.
|
||||
apt__group_repositories: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_repositories [[[
|
||||
#
|
||||
# List of additional APT repositories for specific hosts in Ansible inventory.
|
||||
apt__host_repositories: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__combined_repositories [[[
|
||||
#
|
||||
# Variable which combines all of the repository lists and is used in role tasks
|
||||
# and templates.
|
||||
apt__combined_repositories: '{{ apt__repositories
|
||||
+ apt__group_repositories
|
||||
+ apt__host_repositories }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT authentication files [[[
|
||||
# ----------------------------
|
||||
|
||||
# These lists define APT authentication information for repositories which
|
||||
# require HTTP Basic Authentication to access. See :ref:`apt__ref_auth_files`
|
||||
# for more details.
|
||||
|
||||
# .. envvar:: apt__auth_files [[[
|
||||
#
|
||||
# Authentication configuration files which should be present on all hosts in
|
||||
# the Ansible inventory.
|
||||
apt__auth_files: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_auth_files [[[
|
||||
#
|
||||
# Authentication configuration files which should be present on hosts in
|
||||
# a specific Ansible inventory group.
|
||||
apt__group_auth_files: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_auth_files [[[
|
||||
#
|
||||
# Authentication configuration files which should be present on specific hosts
|
||||
# in the Ansible inventory.
|
||||
apt__host_auth_files: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT configuration files [[[
|
||||
# ---------------------------
|
||||
|
||||
# These lists define additional APT configuration files in
|
||||
# :file:`/etc/apt/apt.conf.d/` directory.
|
||||
# See :ref:`apt__ref_configuration` for more details.
|
||||
|
||||
# .. envvar:: apt__default_configuration [[[
|
||||
#
|
||||
# List of default APT configuration entries defined by the role.
|
||||
apt__default_configuration:
|
||||
|
||||
- name: 'non-free-firmware-note'
|
||||
filename: 'non-free-firmware-note.conf'
|
||||
comment: 'Disable note about Debian Bookworm moving firmware to a separate section'
|
||||
raw: |
|
||||
APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";
|
||||
state: '{{ "ignore"
|
||||
if (apt__distribution == "Debian" and
|
||||
apt__distribution_release in ["wheezy", "jessie", "stretch",
|
||||
"buster", "bullseye"])
|
||||
else "present" }}'
|
||||
|
||||
- name: 'no-recommends'
|
||||
filename: '25no-recommends.conf'
|
||||
comment: 'Should APT install recommended or suggested packages?'
|
||||
raw: |
|
||||
APT::Install-Recommends "false";
|
||||
APT::Install-Suggests "false";
|
||||
state: 'present'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__configuration [[[
|
||||
#
|
||||
# List of additional APT configuration to add on all hosts in Ansible inventory.
|
||||
apt__configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__group_configuration [[[
|
||||
#
|
||||
# List of additional APT configuration to add on hosts in specific Ansible
|
||||
# inventory group.
|
||||
apt__group_configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__host_configuration [[[
|
||||
#
|
||||
# List of additional APT configuration to add on specific hosts in Ansible
|
||||
# inventory.
|
||||
apt__host_configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt__combined_configuration [[[
|
||||
#
|
||||
# Variable which combines all of the APT configuration lists and is used in
|
||||
# role tasks and templates.
|
||||
apt__combined_configuration: '{{ apt__default_configuration
|
||||
+ apt__configuration
|
||||
+ apt__group_configuration
|
||||
+ apt__host_configuration }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
32
ansible_collections/debops/debops/roles/apt/meta/main.yml
Normal file
32
ansible_collections/debops/debops/roles/apt/meta/main.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
# Copyright (C) 2013-2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2014-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski, Robin Schneider'
|
||||
description: 'Manage APT repositories and keys'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.2.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- packages
|
||||
- apt
|
||||
239
ansible_collections/debops/debops/roles/apt/tasks/main.yml
Normal file
239
ansible_collections/debops/debops/roles/apt/tasks/main.yml
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# Copyright (C) 2013-2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2014-2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'debops.debops.global_handlers'
|
||||
|
||||
- name: Import DebOps secret role
|
||||
ansible.builtin.import_role:
|
||||
name: 'debops.debops.secret'
|
||||
|
||||
- name: Validate configuration of APT repositories
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- 'item.filename is defined'
|
||||
- 'item.repo is defined or item.uris is defined or item.state in ["divert", "absent"]'
|
||||
fail_msg: 'You need to specify "filename" and either "repo" or "uris" as parameters'
|
||||
quiet: True
|
||||
loop: '{{ apt__combined_repositories | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
|
||||
- name: Configure custom APT keys
|
||||
ansible.builtin.apt_key:
|
||||
data: '{{ item.data | d(omit) }}'
|
||||
file: '{{ item.file | d(omit) }}'
|
||||
id: '{{ item.id | d(omit) }}'
|
||||
keyring: '{{ item.keyring | d(omit) }}'
|
||||
keyserver: '{{ item.keyserver | d(omit) }}'
|
||||
url: '{{ item.url | d(omit) }}'
|
||||
state: '{{ item.state | d("present") }}'
|
||||
loop: '{{ q("flattened", apt__keys
|
||||
+ apt__group_keys
|
||||
+ apt__host_keys) }}'
|
||||
register: apt__register_apt_key
|
||||
until: apt__register_apt_key is succeeded
|
||||
when: apt__enabled | bool and (item.url | d() or item.data | d() or item.id | d() or item.file | d())
|
||||
tags: [ 'role::apt:keys' ]
|
||||
|
||||
- name: Add/remove diversion of repository sources
|
||||
debops.debops.dpkg_divert:
|
||||
path: '/etc/apt/sources.list.d/{{ item.filename }}'
|
||||
state: '{{ "present"
|
||||
if (item.state | d("present") == "divert")
|
||||
else "absent" }}'
|
||||
delete: True
|
||||
loop: '{{ apt__combined_repositories | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
register: apt__register_divert_repositories
|
||||
when: (apt__enabled | bool and item.filename and item.repo is undefined and item.uris is undefined and
|
||||
(item.state | d("present")) in [ "divert", "absent" ])
|
||||
|
||||
- name: Configure custom APT repositories
|
||||
ansible.builtin.apt_repository:
|
||||
update_cache: False
|
||||
repo: '{{ item.repo }}'
|
||||
codename: '{{ item.codename | d(omit) }}'
|
||||
filename: '{{ item.filename | regex_replace(".list$", "") | regex_replace(".sources$", "") }}'
|
||||
mode: '{{ item.mode | d(omit) }}'
|
||||
state: '{{ item.state | d("present") }}'
|
||||
loop: '{{ apt__combined_repositories | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
register: apt__register_apt_repositories
|
||||
when: (apt__enabled | bool and item.repo | d() and item.uris is undefined and
|
||||
(item.state | d("present")) not in [ "divert", "ignore", "init" ])
|
||||
|
||||
- name: Configure custom APT Deb822 repositories
|
||||
ansible.builtin.deb822_repository:
|
||||
uris: '{{ item.uris }}'
|
||||
name: '{{ item.filename | regex_replace(".sources$", "") | regex_replace(".list$", "") }}'
|
||||
allow_downgrade_to_insecure: '{{ item.allow_downgrade_to_insecure | d(omit) }}'
|
||||
allow_insecure: '{{ item.allow_insecure | d(omit) }}'
|
||||
allow_weak: '{{ item.allow_weak | d(omit) }}'
|
||||
architectures: '{{ item.architectures | d(omit) }}'
|
||||
by_hash: '{{ item.by_hash | d(omit) }}'
|
||||
check_date: '{{ item.check_date | d(omit) }}'
|
||||
check_valid_until: '{{ item.check_valid_until | d(omit) }}'
|
||||
components: '{{ item.components | d(omit) }}'
|
||||
data_max_future: '{{ item.date_max_future | d(omit) }}'
|
||||
enabled: '{{ item.enabled | d(omit) }}'
|
||||
inrelease_path: '{{ item.inrelease_path | d(omit) }}'
|
||||
languages: '{{ item.languages | d(omit) }}'
|
||||
mode: '{{ item.mode | d(omit) }}'
|
||||
pdiffs: '{{ item.pdiffs | d(omit) }}'
|
||||
signed_by: '{{ item.signed_by | d(omit) }}'
|
||||
state: '{{ item.state | d("present") }}'
|
||||
suites: '{{ item.suites | d(omit) }}'
|
||||
targets: '{{ item.targets | d(omit) }}'
|
||||
trusted: '{{ item.trusted | d(omit) }}'
|
||||
types: '{{ item.types | d("deb") }}'
|
||||
loop: '{{ apt__combined_repositories | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
register: apt__register_deb822_repositories
|
||||
when: (apt__enabled|bool and item.uris | d() and item.repo is undefined and
|
||||
(item.state | d("present")) not in [ "divert", "ignore", "init" ])
|
||||
|
||||
- name: Remove APT auth configuration if requested
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apt/auth.conf.d/" + (item.filename | d(item.name | regex_replace(".conf$", "") + ".conf")) }}'
|
||||
state: 'absent'
|
||||
loop: '{{ q("flattened", (apt__auth_files + apt__group_auth_files + apt__host_auth_files)) }}'
|
||||
when: apt__enabled | bool and item.state | d('present') == 'absent'
|
||||
no_log: '{{ debops__no_log | d(True) }}'
|
||||
|
||||
- name: Generate APT auth configuration
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/auth.conf.d/template.conf.j2'
|
||||
dest: '{{ "/etc/apt/auth.conf.d/" + (item.filename | d(item.name | regex_replace(".conf$", "") + ".conf")) }}'
|
||||
mode: '0640'
|
||||
loop: '{{ q("flattened", (apt__auth_files + apt__group_auth_files + apt__host_auth_files)) }}'
|
||||
when: apt__enabled | bool and item.machine | d() and item.login | d() and item.password | d() and
|
||||
item.state | d('present') not in ['absent', 'ignore']
|
||||
no_log: '{{ debops__no_log | d(True) }}'
|
||||
|
||||
- name: Update APT cache on first run
|
||||
ansible.builtin.apt:
|
||||
update_cache: True
|
||||
cache_valid_time: '{{ apt__cache_valid_time }}'
|
||||
register: apt__register_apt_first_update
|
||||
until: apt__register_apt_first_update is succeeded
|
||||
when: (apt__enabled | bool and
|
||||
not (ansible_local.apt.configured | d()) | bool)
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.apt:
|
||||
name: '{{ (apt__base_packages + apt__packages) | flatten }}'
|
||||
state: 'present'
|
||||
install_recommends: False
|
||||
register: apt__register_packages
|
||||
until: apt__register_packages is succeeded
|
||||
when: apt__enabled | bool
|
||||
|
||||
- name: Enable extra architectures
|
||||
ansible.builtin.command: dpkg --add-architecture {{ item }}
|
||||
loop: '{{ q("flattened", apt__extra_architectures
|
||||
+ apt__group_extra_architectures
|
||||
+ apt__host_extra_architectures) }}'
|
||||
register: apt__register_add_architecture
|
||||
changed_when: apt__register_add_architecture.changed | bool
|
||||
when: apt__enabled | bool and item not in ansible_facts.ansible_local.apt.foreign_architectures | d()
|
||||
notify: [ 'Refresh host facts' ]
|
||||
|
||||
- name: Add/remove diversion of APT configuration files
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ "/etc/apt/apt.conf.d/" + (item.filename | d(item.name | regex_replace(".conf$", "") + ".conf")) }}'
|
||||
state: '{{ "present"
|
||||
if (item.state | d("present") == "divert")
|
||||
else "absent" }}'
|
||||
delete: True
|
||||
loop: '{{ apt__combined_configuration | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: apt__enabled | bool and item.state | d("present") in [ "divert", "absent" ]
|
||||
|
||||
- name: Delete APT configuration files on remote hosts
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apt/apt.conf.d/" + (item.filename | d(item.name | regex_replace(".conf$", "") + ".conf")) }}'
|
||||
state: 'absent'
|
||||
loop: '{{ apt__combined_configuration | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: apt__enabled | bool and item.raw | d() and item.state | d('present') == 'absent'
|
||||
|
||||
- name: Generate APT configuration files
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/apt.conf.d/template.conf.j2'
|
||||
dest: '{{ "/etc/apt/apt.conf.d/" + (item.filename | d(item.name | regex_replace(".conf$", "") + ".conf")) }}'
|
||||
mode: '0644'
|
||||
loop: '{{ apt__combined_configuration | debops.debops.parse_kv_items }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: apt__enabled | bool and item.raw | d() and
|
||||
item.state | d('present') not in [ 'divert', 'absent', 'ignore', 'init' ]
|
||||
|
||||
- name: Make sure that Ansible local facts directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
mode: '0755'
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Save APT local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apt.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apt.fact'
|
||||
mode: '0755'
|
||||
notify: [ 'Refresh host facts' ]
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Update Ansible facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
||||
- name: Add/remove diversion of /etc/apt/sources.list
|
||||
debops.debops.dpkg_divert:
|
||||
path: '/etc/apt/sources.list'
|
||||
state: '{{ apt__deploy_state }}'
|
||||
delete: True
|
||||
register: apt__register_sources_diversion
|
||||
when: (apt__enabled | bool and apt__deploy_state in ['absent', 'present'])
|
||||
|
||||
- name: Configure operating system sources.list
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/sources.list.j2'
|
||||
dest: '/etc/apt/sources.list'
|
||||
mode: '0644'
|
||||
register: apt__register_sources_template
|
||||
when: (apt__enabled | bool and apt__deploy_state == 'present')
|
||||
|
||||
- name: Update APT cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: True
|
||||
cache_valid_time: '{{ omit
|
||||
if (apt__register_sources_template is changed or
|
||||
apt__register_sources_diversion is changed or
|
||||
apt__register_apt_repositories is changed)
|
||||
else apt__cache_valid_time }}'
|
||||
register: apt__register_apt_update
|
||||
until: apt__register_apt_update is succeeded
|
||||
when: apt__enabled | bool
|
||||
|
||||
- name: Purge APT packages if requested
|
||||
ansible.builtin.apt:
|
||||
name: '{{ (apt__purge_packages
|
||||
+ apt__purge_group_packages
|
||||
+ apt__purge_host_packages) | flatten }}'
|
||||
state: 'absent'
|
||||
purge: True
|
||||
autoremove: True
|
||||
register: apt__register_purge_packages
|
||||
until: apt__register_purge_packages is succeeded
|
||||
when: apt__enabled | bool
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2013-2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2014-2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import loads, dumps
|
||||
from sys import exit
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
sources_list = ['/etc/apt/sources.list.dpkg-divert',
|
||||
'/etc/apt/sources.list']
|
||||
|
||||
nonfree_components = ['non-free', 'restricted', 'multiverse']
|
||||
nonfree_firmware_components = ['non-free-firmware']
|
||||
|
||||
output = loads('''{{ ({
|
||||
"enabled": apt__enabled,
|
||||
"configured": True,
|
||||
"components": [],
|
||||
"nonfree": False,
|
||||
"nonfree_firmware": False}) | to_nice_json }}''')
|
||||
|
||||
try:
|
||||
|
||||
for sources_file in sources_list:
|
||||
if (os.path.isfile(sources_file)
|
||||
and os.access(sources_file, os.R_OK)):
|
||||
fh = open(sources_file)
|
||||
|
||||
for line in fh:
|
||||
if (line.startswith('deb') or
|
||||
line.startswith('deb-src')):
|
||||
source = line.split()
|
||||
for component in source[3:]:
|
||||
if component not in output['components']:
|
||||
output['components'].append(component)
|
||||
if component in nonfree_components:
|
||||
output['nonfree'] = True
|
||||
if component in nonfree_firmware_components:
|
||||
output['nonfree_firmware'] = True
|
||||
|
||||
fh.close()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
main_arch = subprocess.check_output(
|
||||
['dpkg', '--print-architecture'],
|
||||
stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||
if main_arch:
|
||||
output.update({'architecture': main_arch})
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
try:
|
||||
foreign_arch = subprocess.check_output(
|
||||
['dpkg', '--print-foreign-architectures'],
|
||||
stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||
if foreign_arch:
|
||||
output.update({'foreign_architectures':
|
||||
foreign_arch.split('\n')})
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
// {{ ansible_managed }}
|
||||
|
||||
{% if item.comment | d() %}
|
||||
{{ item.comment | regex_replace('\n$', '') | comment(decoration='// ', prefix='', postfix='') -}}
|
||||
{% endif %}
|
||||
{% if item.raw | d() %}
|
||||
{{ item.raw | regex_replace('\n$', '') -}}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{# Copyright (C) 2021 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2021 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Authentication credentials for "{{ item.name }}" APT repository
|
||||
|
||||
{% if item.comment | d() %}
|
||||
{{ item.comment | regex_replace('\n$','') | comment(prefix='', postfix='') }}
|
||||
{% endif %}
|
||||
{{ 'machine {} login {} password {}'.format(item.machine, item.login, item.password) }}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
{# Copyright (C) 2013-2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2014-2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for element in apt__combined_sources | debops.debops.parse_kv_items(merge_keys=['types', 'uris', 'suites', 'components']) %}
|
||||
{% if element.state not in ['absent', 'ignore', 'init'] %}
|
||||
{% set element_comment = ('#' if (element.state == 'comment') else '') %}
|
||||
{% if element.comment | d() %}
|
||||
{{ element.comment | regex_replace('\n$', '') | comment(prefix='', postfix='') -}}
|
||||
{% endif %}
|
||||
{% if element.raw | d() %}
|
||||
{% if element_comment %}
|
||||
{{ element.raw | regex_replace('\n$', '') | comment(decoration='#', prefix='', postfix='') -}}
|
||||
{% else %}
|
||||
{{ element.raw | regex_replace('\n$', '') }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% set types = [] %}
|
||||
{% set uris = [] %}
|
||||
{% set suites = [] %}
|
||||
{% set components = [] %}
|
||||
{% if element.type | d() %}
|
||||
{% set _ = types.append(element.type) %}
|
||||
{% endif %}
|
||||
{% if element.types | d() %}
|
||||
{% set _ = types.extend(element.types | selectattr('state', 'equalto', 'present') | map(attribute='name') | list) %}
|
||||
{% endif %}
|
||||
{% if not types %}
|
||||
{% set _ = types.extend(apt__archive_types) %}
|
||||
{% endif %}
|
||||
{% if element.uri | d() %}
|
||||
{% set _ = uris.append(element.uri) %}
|
||||
{% endif %}
|
||||
{% if element.uris | d() %}
|
||||
{% set _ = uris.extend(element.uris | selectattr('state', 'equalto', 'present') | map(attribute='name') | list) %}
|
||||
{% endif %}
|
||||
{% if element.suite | d() %}
|
||||
{% set _ = suites.append(element.suite) %}
|
||||
{% endif %}
|
||||
{% if element.suites | d() %}
|
||||
{% set suites = element.suites | selectattr('state', 'equalto', 'present') | map(attribute='name') | list %}
|
||||
{% endif %}
|
||||
{% if element.component | d() %}
|
||||
{% set _ = components.append(element.component) %}
|
||||
{% endif %}
|
||||
{% if element.components | d() %}
|
||||
{% set components = element.components | selectattr('state', 'equalto', 'present') | map(attribute='name') | list %}
|
||||
{% endif %}
|
||||
{% set source_options = '' %}
|
||||
{% set parsed_options = [] %}
|
||||
{% if element.options | d() %}
|
||||
{% for option in element.options %}
|
||||
{% if option.value is string %}
|
||||
{% set option_string = option.name + '=' + option.value %}
|
||||
{% else %}
|
||||
{% set option_string = option.name + '=' + option.value | selectattr('state', 'equalto', 'present') | map(attribute='name') | list | join(',') %}
|
||||
{% endif %}
|
||||
{% set _ = parsed_options.append(option_string) %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if parsed_options %}
|
||||
{% set source_options = ' [' + parsed_options | join(' ') + ']' %}
|
||||
{% endif %}
|
||||
{% for uri in uris %}
|
||||
{% for suite in suites %}
|
||||
{% for type in types %}
|
||||
{% if type == 'deb-src' and apt__archive_sources_disabled | bool %}
|
||||
{% set element_comment = '#' %}
|
||||
{% else %}
|
||||
{% set element_comment = ('#' if (element.state == 'comment') else '') %}
|
||||
{% endif %}
|
||||
{{ '{}{}{} {} {} {}'.format(element_comment, type, source_options, uri, suite, components | join(' ')) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if element.separate | d(True) and not loop.last %}
|
||||
{{ '' }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
debops.apt_cacher_ng - Install and manage the caching HTTP proxy Apt-Cacher NG
|
||||
|
||||
Copyright (C) 2016-2017,2021 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2016-2017,2021 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,591 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_cacher_ng__ref_defaults:
|
||||
|
||||
# debops.apt_cacher_ng default variables [[[
|
||||
# ==========================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# Packages and installation [[[
|
||||
# -----------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__base_packages [[[
|
||||
#
|
||||
# List of base packages to install.
|
||||
apt_cacher_ng__base_packages:
|
||||
- 'apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__enabled [[[
|
||||
#
|
||||
# Should the Apt-Cacher NG service be enabled?
|
||||
apt_cacher_ng__enabled: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__deploy_state [[[
|
||||
#
|
||||
# What is the desired state which this role should achieve? Possible options:
|
||||
#
|
||||
# ``present``
|
||||
# Default. Ensure that Apt-Cacher NG is installed and configured as requested.
|
||||
#
|
||||
# ``absent``
|
||||
# Ensure that Apt-Cacher NG is uninstalled and it's configuration is removed.
|
||||
#
|
||||
# ``purge``
|
||||
# Same as ``absent`` but additionally also ensures that the cache directories
|
||||
# is removed.
|
||||
#
|
||||
apt_cacher_ng__deploy_state: 'present'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__configuration_files [[[
|
||||
#
|
||||
# This variable allows you to change which configuration files this role is
|
||||
# going to create and which permissions to use for them.
|
||||
#
|
||||
# ``path``
|
||||
# String, required, defines the path to the configuration file on the host.
|
||||
#
|
||||
# ``src``
|
||||
# String, optional, defines the path to the template file. Defaults to
|
||||
# ``path`` with any leading ``/`` removed.
|
||||
#
|
||||
# ``owner``
|
||||
# String, optional, defaults to ``root``. Unix user which owns the
|
||||
# configuration file.
|
||||
#
|
||||
# ``group``
|
||||
# String, optional, defaults to ``root``. Unix group of the configuration file.
|
||||
#
|
||||
# ``mode``
|
||||
# String, optional, defaults to ``0640``. Unix permissions of the
|
||||
# configuration file.
|
||||
#
|
||||
# ``divert``
|
||||
# Boolean, optional, defaults to ``True``. Should the original configuration file
|
||||
# be diverted away before creating our version of the file?
|
||||
#
|
||||
apt_cacher_ng__configuration_files:
|
||||
|
||||
- path: '/etc/apt-cacher-ng/backends_debian'
|
||||
mode: '0644'
|
||||
- path: '/etc/apt-cacher-ng/backends_ubuntu'
|
||||
mode: '0644'
|
||||
- path: '/etc/apt-cacher-ng/backends_gentoo'
|
||||
mode: '0644'
|
||||
divert: False
|
||||
- path: '/etc/apt-cacher-ng/acng.conf'
|
||||
mode: '0644'
|
||||
- path: '/etc/apt-cacher-ng/security.conf'
|
||||
group: 'apt-cacher-ng'
|
||||
mode: '0640'
|
||||
- path: '/etc/apt-cacher-ng/userinfo.html'
|
||||
mode: '0644'
|
||||
divert: False
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Network related settings [[[
|
||||
# ----------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__port [[[
|
||||
#
|
||||
# TCP server port for incoming http (or HTTP proxy) connections.
|
||||
# Can be set to ``9999`` to emulate :program:`apt-proxy`.
|
||||
apt_cacher_ng__port: 3142
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__bind_address [[[
|
||||
#
|
||||
# List of addresses or hostnames to listen on. Each entry must be an exact
|
||||
# local address which is associated with a local interface. DNS resolution is
|
||||
# performed using :manpage:`getaddrinfo(3)` for all available protocols (IPv4,
|
||||
# IPv6, ...). Using a protocol specific format will create binding(s) only on
|
||||
# protocol specific socket(s), e. g. ``0.0.0.0`` will listen only to IPv4.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_cacher_ng__bind_address:
|
||||
# - 'localhost'
|
||||
# - '192.168.7.254'
|
||||
# - 'publicNameOnMainInterface'
|
||||
#
|
||||
# Defaults to listening on all interfaces and protocols.
|
||||
apt_cacher_ng__bind_address: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__fqdn [[[
|
||||
#
|
||||
# The FQDN subdomain of the Apt-Cacher NG proxy which will be used by
|
||||
# :program:`nginx` webserver.
|
||||
apt_cacher_ng__fqdn: 'software-cache.{{ ansible_domain }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__proxy [[[
|
||||
#
|
||||
# The specification of another HTTP proxy which shall be used for downloads.
|
||||
# It can include user name and password but see the manual for limitations.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_cacher_ng__proxy: 'https://username:proxypassword@proxy.example.net:3129'
|
||||
#
|
||||
# Defaults to using a direct connection.
|
||||
apt_cacher_ng__proxy: ''
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__connect_protocol [[[
|
||||
#
|
||||
# Specifies the IP protocol families to use for remote connections. Order does
|
||||
# matter, first specified are considered first.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_cacher_ng__connect_protocol:
|
||||
# - 'v4'
|
||||
# # - 'v6'
|
||||
#
|
||||
# Only use IPv4 connections for connecting to upstream mirrors.
|
||||
#
|
||||
# Defaults to using native order of the system's TCP/IP stack, influenced by
|
||||
# the :envvar:`apt_cacher_ng__bind_address` value.
|
||||
apt_cacher_ng__connect_protocol: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__offline_mode [[[
|
||||
#
|
||||
# Forbid outgoing connections and work without an internet connection or
|
||||
# respond with 503 error where it's not possible.
|
||||
apt_cacher_ng__offline_mode: False
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__network_timeout [[[
|
||||
#
|
||||
# Network timeout for outgoing connections, in seconds.
|
||||
apt_cacher_ng__network_timeout: 60
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__max_download_speed_kib [[[
|
||||
#
|
||||
# It's possible to limit the processing speed of download agents to set an
|
||||
# overall download speed limit. Unit: KiB/s, Default: unlimited.
|
||||
apt_cacher_ng__max_download_speed_kib: ''
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Upstream mirrors [[[
|
||||
# --------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__upstream_mirror_debian [[[
|
||||
#
|
||||
# Which upstream mirror(s) should be used for Debian repositories?
|
||||
# One mirror per line.
|
||||
# Set to an empty string to let the package scripts from Apt-Cacher NG decide
|
||||
# which upstream mirror to use.
|
||||
apt_cacher_ng__upstream_mirror_debian: '{{ ansible_local.apt.default_sources_map.Debian[0]
|
||||
| d("http://deb.debian.org/debian") }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__upstream_mirror_ubuntu [[[
|
||||
#
|
||||
# Which upstream mirror(s) should be used for Ubuntu repositories?
|
||||
# One mirror per line.
|
||||
# Set to an empty string to let the package scripts from Apt-Cacher NG decide
|
||||
# which upstream mirror to use.
|
||||
apt_cacher_ng__upstream_mirror_ubuntu: '{{ ansible_local.apt.default_sources_map.Ubuntu[0]
|
||||
| d("http://archive.ubuntu.com/ubuntu") }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__upstream_mirror_gentoo [[[
|
||||
#
|
||||
# Which upstream mirror(s) should be used for Gentoo repositories?
|
||||
# One mirror per line.
|
||||
# Set to an empty string to let the package scripts from Apt-Cacher NG decide
|
||||
# which upstream mirror to use.
|
||||
apt_cacher_ng__upstream_mirror_gentoo: '{{ ansible_local.apt.default_sources_map.Gentoo[0] | d("") }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Cache directory [[[
|
||||
# -------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__cache_dir [[[
|
||||
#
|
||||
# Storage directory for downloaded data and related maintenance activity.
|
||||
apt_cacher_ng__cache_dir: '/var/cache/apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__cache_dir_owner [[[
|
||||
#
|
||||
# Unix user which owns the cache directory and it's contents.
|
||||
apt_cacher_ng__cache_dir_owner: 'apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__cache_dir_group [[[
|
||||
#
|
||||
# Unix group of the cache directory and it's contents..
|
||||
apt_cacher_ng__cache_dir_group: 'apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__dir_perms [[[
|
||||
#
|
||||
# Default permission set of freshly created files and directories, as octal
|
||||
# numbers (see :manpage:`chmod(1)` for details).
|
||||
# Can by limited by the umask value (see :manpage:`umask(2)` for details) if it's set in
|
||||
# the environment of the starting shell, e. g. in apt-cacher-ng init script or
|
||||
# in its configuration file.
|
||||
apt_cacher_ng__dir_perms: '02755'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__file_perms [[[
|
||||
#
|
||||
# Default permission set of freshly created files and directories, as octal
|
||||
# numbers (see :manpage:`chmod(1)` for details).
|
||||
# Can by limited by the umask value (see :manpage:`umask(2)` for details) if it's set in
|
||||
# the environment of the starting shell, e. g. in apt-cacher-ng init script or
|
||||
# in its configuration file.
|
||||
apt_cacher_ng__file_perms: '00644'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__cache_dir_enforce_permissions [[[
|
||||
#
|
||||
# Should the permissions of the cache directory and it's content be enforced
|
||||
# (changed to the specified owner, group and mode)?
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# ``strict``
|
||||
# Go thought all files and directories and enforce the permissions on each Ansible run.
|
||||
#
|
||||
# .. warning:: This can slow down the role execution time even
|
||||
# when the changes have already been applied. The main factor is
|
||||
# the number of files/directories in your cache directory.
|
||||
#
|
||||
# ``lazy``
|
||||
# Check the :file:`_expending_damaged` file in the root of
|
||||
# :envvar:`apt_cacher_ng__cache_dir` and only enforce permissions on all other
|
||||
# files if this one file needed to be changed.
|
||||
#
|
||||
# ``disabled``
|
||||
# Don't enforce permissions.
|
||||
#
|
||||
apt_cacher_ng__cache_dir_enforce_permissions: 'lazy'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Management credentials [[[
|
||||
# --------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__user [[[
|
||||
#
|
||||
# Username for basic authentication required to visit pages with administrative
|
||||
# functionality.
|
||||
apt_cacher_ng__user: 'admin'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__password [[[
|
||||
#
|
||||
# Password for basic authentication required to visit pages with administrative
|
||||
# functionality.
|
||||
apt_cacher_ng__password: '{{ lookup("password", secret + "/credentials/" +
|
||||
inventory_hostname + "/apt_cacher_ng/" +
|
||||
apt_cacher_ng__user + "/password length=24") }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Tuning, debugging and further options [[[
|
||||
# -----------------------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__log_dir [[[
|
||||
#
|
||||
# Log file directory, can be set empty to disable logging.
|
||||
apt_cacher_ng__log_dir: '/var/log/apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__support_dir [[[
|
||||
#
|
||||
# A place to look for additional configuration and resource files if they are not
|
||||
# found in the configuration directory.
|
||||
apt_cacher_ng__support_dir: '/usr/lib/apt-cacher-ng'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__debug [[[
|
||||
#
|
||||
# A bitmask type value declaring the logging verbosity and behavior of the error
|
||||
# log writing. Non-zero value triggers at least faster log file flushing.
|
||||
#
|
||||
# Some higher bits only working with a special debug build of apt-cacher-ng,
|
||||
# see the manual for details. The setting has an alias named ``UnbufferLogs``.
|
||||
# Setting ``apt_cacher_ng__debug: 1`` will result in unbuffer log writes.
|
||||
#
|
||||
# .. warning:: This can write significant amount of data into the
|
||||
# :file:`apt-cacher.err` logfile.
|
||||
#
|
||||
# 0. No debug printing.
|
||||
#
|
||||
# 1. Log file buffers are flushed faster.
|
||||
#
|
||||
# 2. Some additional information appears within usual transfer/error logs.
|
||||
#
|
||||
# 4. Extra debug information is written to apt-cacher.err (also enables lots of additional trace
|
||||
# points when apt-cacher-ng binary is built with debug configuration, see section 9.6 for
|
||||
# details).
|
||||
#
|
||||
apt_cacher_ng__debug: 0
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__verbose_log [[[
|
||||
#
|
||||
# Enables extended client information in log entries. When set to ``True``,
|
||||
# only activity type, time and transfer sizes are logged.
|
||||
apt_cacher_ng__verbose_log: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__force_managed [[[
|
||||
#
|
||||
# Forbid downloads from locations that are directly specified in the user
|
||||
# request, i.e. all downloads must be processed by the preconfigured remapping
|
||||
# backends.
|
||||
# Set to ``False`` by default to allow to download other repositories via the proxy like
|
||||
# `download.owncloud.org <https://download.owncloud.org/download/repositories/>`_.
|
||||
apt_cacher_ng__force_managed: False
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__expiration_threshold [[[
|
||||
#
|
||||
# Days before considering an unreferenced file expired (to be deleted).
|
||||
#
|
||||
# .. warning:: If the value is set too low and particular index files are not
|
||||
# available for some days (mirror downtime) then there is a risk of removal of
|
||||
# still useful package files.
|
||||
#
|
||||
apt_cacher_ng__expiration_threshold: 4
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__expiration_abort_on_problems [[[
|
||||
#
|
||||
# Stop expiration when a critical problem appears, issue like a failed update
|
||||
# of an index file in the preparation step.
|
||||
#
|
||||
# .. warning:: Don't set this option to zero or empty without considering possible
|
||||
# consequences like a sudden and complete cache data loss.
|
||||
#
|
||||
apt_cacher_ng__expiration_abort_on_problems: 'default'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__dns_cache_seconds [[[
|
||||
#
|
||||
# There is a small in-memory cache for DNS resolution data, expired by
|
||||
# this timeout (in seconds). Internal caching is disabled if set to a value
|
||||
# less than zero.
|
||||
apt_cacher_ng__dns_cache_seconds: 1800
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__log_submitted_origin [[[
|
||||
#
|
||||
# Trust the downstream HTTP proxy and log the X-Forwarded-For header as the
|
||||
# client IP address.
|
||||
apt_cacher_ng__log_submitted_origin: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__user_agent [[[
|
||||
#
|
||||
# The version string reported to the peer, to be displayed as HTTP client (and
|
||||
# version) in the logs of the mirror.
|
||||
#
|
||||
# .. warning:: Expect side effects! Some archives use this header to guess
|
||||
# capabilities of the client (i.e. allow redirection and/or https links) and
|
||||
# change their behaviour accordingly but ACNG might not support the expected
|
||||
# features.
|
||||
#
|
||||
# Default is the compiled in UserAgent: Yet Another HTTP Client/1.2.3p4
|
||||
apt_cacher_ng__user_agent: 'default'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__recompress_bz2 [[[
|
||||
#
|
||||
# In some cases the Import and Expiration tasks might create fresh volatile
|
||||
# data for internal use by reconstructing them using patch files. This
|
||||
# by-product might be recompressed with bzip2 and with some luck the resulting
|
||||
# file becomes identical to the ``*.bz2`` file on the server which can be used by
|
||||
# APT when requesting a complete version of this file.
|
||||
# The downside of this feature is higher CPU load on the server during
|
||||
# the maintenance tasks, and the outcome might have not much value in a LAN
|
||||
# where all clients update their data often and regularly and therefore usually
|
||||
# don't need the full version of the index file.
|
||||
apt_cacher_ng__recompress_bz2: False
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__custom [[[
|
||||
#
|
||||
# Configuration block for Apt-Cacher NG for additional configuration for
|
||||
# example custom remap settings.
|
||||
apt_cacher_ng__custom: ''
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Network accessibility [[[
|
||||
# -------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__allow [[[
|
||||
#
|
||||
# Allow access to Apt-Cacher NG from specified IP addresses or CIDR networks.
|
||||
# If not specified, allows access from all networks.
|
||||
apt_cacher_ng__allow: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__group_allow [[[
|
||||
#
|
||||
# Allow access to Apt-Cacher NG from specified IP addresses or CIDR networks.
|
||||
# If not specified, allows access from all networks.
|
||||
apt_cacher_ng__group_allow: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__host_allow [[[
|
||||
#
|
||||
# Allow access to Apt-Cacher NG from specified IP addresses or CIDR networks.
|
||||
# If not specified, allows access from all networks.
|
||||
apt_cacher_ng__host_allow: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__interfaces [[[
|
||||
#
|
||||
# List of network interfaces from which to allow access to Apt-Cacher NG.
|
||||
# If not specified, allows access from all interfaces.
|
||||
apt_cacher_ng__interfaces: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Role-dependent configuration [[[
|
||||
# --------------------------------
|
||||
|
||||
# .. envvar:: apt_cacher_ng__etc_services__dependent_list [[[
|
||||
#
|
||||
# Configuration for the :ref:`debops.etc_services` role which registers port
|
||||
# numbers for Apt-Cacher NG.
|
||||
apt_cacher_ng__etc_services__dependent_list:
|
||||
|
||||
- name: 'acng'
|
||||
port: '{{ apt_cacher_ng__port }}'
|
||||
comment: 'Apt-Cacher NG caching proxy server'
|
||||
delete: '{{ apt_cacher_ng__deploy_state != "present" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__apt_preferences__dependent_list [[[
|
||||
#
|
||||
# Configuration for the :ref:`debops.apt_preferences` role.
|
||||
apt_cacher_ng__apt_preferences__dependent_list: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__ferm__dependent_rules [[[
|
||||
#
|
||||
# Configuration for :command:`ferm` firewall. It should be added when
|
||||
# :ref:`debops.ferm` role is used to configure Apt-Cacher NG firewall rules.
|
||||
apt_cacher_ng__ferm__dependent_rules:
|
||||
|
||||
- type: 'accept'
|
||||
dport: [ 'acng' ]
|
||||
saddr: '{{ (apt_cacher_ng__allow | d([]) | list) +
|
||||
(apt_cacher_ng__group_allow | d([]) | list) +
|
||||
(apt_cacher_ng__host_allow | d([]) | list) }}'
|
||||
accept_any: True
|
||||
interface: '{{ apt_cacher_ng__interfaces }}'
|
||||
weight: '40'
|
||||
by_role: 'debops.apt_cacher_ng'
|
||||
name: 'http_proxy'
|
||||
rule_state: '{{ apt_cacher_ng__deploy_state }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__apparmor__dependent_config [[[
|
||||
#
|
||||
# Configuration for the ``debops-contrib.apparmor`` role.
|
||||
apt_cacher_ng__apparmor__dependent_config:
|
||||
|
||||
'usr.sbin.apt-cacher-ng':
|
||||
## Seems this change is not possible thought the ``@{APT_CACHE_DIR}``
|
||||
## variable without changing the profile file directly?
|
||||
- comment: 'Allow Apt-Cacher-Ng access to the cache directory'
|
||||
by_role: 'debops.apt_cacher_ng'
|
||||
delete: '{{ apt_cacher_ng__deploy_state != "present" }}'
|
||||
rules:
|
||||
- '{{ apt_cacher_ng__cache_dir }}/ r'
|
||||
- '{{ apt_cacher_ng__cache_dir }}/** rw'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__upstream_servers [[[
|
||||
#
|
||||
# List of upstream :program:`nginx` proxy servers.
|
||||
apt_cacher_ng__upstream_servers:
|
||||
- 'localhost:{{ apt_cacher_ng__port }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__nginx__upstream [[[
|
||||
#
|
||||
# The :program:`nginx` upstream configuration, managed by :ref:`debops.nginx` role.
|
||||
apt_cacher_ng__nginx__upstream:
|
||||
enabled: True
|
||||
name: 'apt-cacher-ng'
|
||||
server: '{{ apt_cacher_ng__upstream_servers }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_cacher_ng__nginx__servers [[[
|
||||
#
|
||||
# List of :program:`nginx` server configurations managed by the
|
||||
# :ref:`debops.nginx` role.
|
||||
# There is a separate configuration for HTTP and HTTPS
|
||||
# connections to allow access for hosts without SSL support installed.
|
||||
apt_cacher_ng__nginx__servers:
|
||||
|
||||
- by_role: 'debops.apt_cacher_ng'
|
||||
name: [ '{{ apt_cacher_ng__fqdn }}' ]
|
||||
filename: 'debops.apt_cacher_ng_http'
|
||||
enabled: True
|
||||
allow: '{{ apt_cacher_ng__allow + apt_cacher_ng__group_allow + apt_cacher_ng__host_allow }}'
|
||||
ssl: False
|
||||
webroot_create: False
|
||||
type: 'proxy'
|
||||
proxy_pass: 'http://apt-cacher-ng'
|
||||
proxy_options: |
|
||||
if ($request_uri !~ "^/.*(\.js|\.css|\.html|\.ico)(.*)?$") {
|
||||
rewrite ^/(.*)$ /$host/$1 break;
|
||||
}
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
options: |
|
||||
location ~ /acng-report.html {
|
||||
return 307 https://$host$request_uri;
|
||||
}
|
||||
|
||||
- by_role: 'debops.apt_cacher_ng'
|
||||
name: [ '{{ apt_cacher_ng__fqdn }}' ]
|
||||
filename: 'debops.apt_cacher_ng_https'
|
||||
enabled: True
|
||||
allow: '{{ apt_cacher_ng__allow + apt_cacher_ng__group_allow + apt_cacher_ng__host_allow }}'
|
||||
state: '{{ "present" if (ansible_local.pki | d()) else "absent" }}'
|
||||
listen: False
|
||||
webroot_create: False
|
||||
type: 'proxy'
|
||||
proxy_pass: 'http://apt-cacher-ng'
|
||||
proxy_options: |
|
||||
if ($request_uri !~ "^/.*(\.js|\.css|\.html|\.ico)(.*)?$") {
|
||||
rewrite ^/(.*)$ /$host/$1 break;
|
||||
}
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
|
||||
# ]]]
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017,2021 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Robin Schneider'
|
||||
description: 'Install and manage the caching HTTP proxy Apt-Cacher NG'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.0.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- proxy
|
||||
- caching
|
||||
- packages
|
||||
- apt
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017,2021 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Import DebOps secret role
|
||||
ansible.builtin.import_role:
|
||||
name: 'secret'
|
||||
|
||||
- name: Disable autoconfiguration
|
||||
ansible.builtin.debconf:
|
||||
name: 'apt-cacher-ng'
|
||||
question: 'apt-cacher-ng/gentargetmode'
|
||||
vtype: 'select'
|
||||
value: 'No automated setup'
|
||||
when: apt_cacher_ng__deploy_state == 'present'
|
||||
|
||||
- name: Add/remove configuration file diversions
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ item.path }}'
|
||||
state: '{{ "present" if apt_cacher_ng__deploy_state == "present"
|
||||
else "absent" }}'
|
||||
delete: True
|
||||
loop: '{{ apt_cacher_ng__configuration_files }}'
|
||||
when: item.divert | d(True)
|
||||
|
||||
- name: Install/remove packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", apt_cacher_ng__base_packages) }}'
|
||||
state: '{{ "present" if apt_cacher_ng__deploy_state == "present"
|
||||
else "absent" }}'
|
||||
register: apt_cacher_ng__register_packages
|
||||
until: apt_cacher_ng__register_packages is succeeded
|
||||
|
||||
- name: Generate configuration files
|
||||
ansible.builtin.template:
|
||||
src: '{{ item.src | d(item.path | regex_replace("^/", "")) }}.j2'
|
||||
dest: '{{ item.path }}'
|
||||
owner: '{{ item.owner | d("root") }}'
|
||||
group: '{{ item.group | d("root") }}'
|
||||
mode: '{{ item.mode | d("0640") }}'
|
||||
loop: '{{ apt_cacher_ng__configuration_files }}'
|
||||
notify: [ 'Restart apt-cacher-ng' ]
|
||||
when: apt_cacher_ng__deploy_state == 'present'
|
||||
|
||||
- name: Create the cache directory
|
||||
ansible.builtin.file:
|
||||
state: 'directory'
|
||||
path: '{{ apt_cacher_ng__cache_dir }}'
|
||||
owner: '{{ apt_cacher_ng__cache_dir_owner }}'
|
||||
group: '{{ apt_cacher_ng__cache_dir_group }}'
|
||||
mode: '{{ apt_cacher_ng__dir_perms }}'
|
||||
when: apt_cacher_ng__deploy_state == 'present'
|
||||
|
||||
- name: Lazy check cache directory permissions
|
||||
ansible.builtin.file:
|
||||
state: 'file'
|
||||
path: '{{ apt_cacher_ng__cache_dir }}/_expending_damaged'
|
||||
owner: '{{ apt_cacher_ng__cache_dir_owner }}'
|
||||
group: '{{ apt_cacher_ng__cache_dir_group }}'
|
||||
mode: '{{ apt_cacher_ng__file_perms }}'
|
||||
failed_when: False
|
||||
register: apt_cacher_ng__register_cache_perms
|
||||
when: (apt_cacher_ng__deploy_state == 'present' and
|
||||
apt_cacher_ng__cache_dir_enforce_permissions == 'lazy')
|
||||
|
||||
# Note: doing this using native Ansible tasks is too slow
|
||||
- name: Change cache directory permissions # noqa no-free-form
|
||||
ansible.builtin.shell: |
|
||||
chown --recursive {{ apt_cacher_ng__cache_dir_owner }}:{{ apt_cacher_ng__cache_dir_group }} .
|
||||
find . -type d -exec chmod {{ apt_cacher_ng__dir_perms }} {} \;
|
||||
find . -type f -exec chmod {{ apt_cacher_ng__file_perms }} {} \;
|
||||
args:
|
||||
chdir: '{{ apt_cacher_ng__cache_dir }}'
|
||||
register: apt_cacher_ng__register_chmod
|
||||
changed_when: apt_cacher_ng__register_chmod.changed | bool
|
||||
when: (apt_cacher_ng__deploy_state == 'present' and
|
||||
(apt_cacher_ng__cache_dir_enforce_permissions == "strict" or
|
||||
(apt_cacher_ng__cache_dir_enforce_permissions == "lazy" and
|
||||
apt_cacher_ng__register_cache_perms is changed)))
|
||||
|
||||
- name: Enable/disable service
|
||||
ansible.builtin.service:
|
||||
name: 'apt-cacher-ng'
|
||||
state: '{{ "started" if apt_cacher_ng__enabled | d(True) else "stopped" }}'
|
||||
enabled: '{{ True if apt_cacher_ng__enabled | d(True) else False }}'
|
||||
when: apt_cacher_ng__deploy_state == 'present'
|
||||
|
||||
- name: Remove configuration files
|
||||
ansible.builtin.file:
|
||||
path: '{{ item.path }}'
|
||||
state: 'absent'
|
||||
loop: '{{ apt_cacher_ng__configuration_files }}'
|
||||
when: (apt_cacher_ng__deploy_state in ['absent', 'purge'] and
|
||||
not item.divert | d(True))
|
||||
|
||||
- name: Remove the cache directory
|
||||
ansible.builtin.file:
|
||||
path: '{{ apt_cacher_ng__cache_dir }}'
|
||||
state: 'absent'
|
||||
when: apt_cacher_ng__deploy_state == 'purge'
|
||||
|
|
@ -0,0 +1,590 @@
|
|||
{# Copyright (C) 2016-2017,2021 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017,2021 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
#
|
||||
# IMPORTANT NOTE:
|
||||
#
|
||||
# THIS FILE IS MAYBE JUST ONE OF MANY CONFIGURATION FILES IN THIS DIRECTORY.
|
||||
# SETTINGS MADE IN OTHER FILES CAN OVERRIDE VALUES THAT YOU CHANGE HERE. GO
|
||||
# LOOK FOR OTHER CONFIGURATION FILES! CHECK THE MANUAL AND INSTALLATION NOTES
|
||||
# (like README.Debian) FOR MORE DETAILS!
|
||||
#
|
||||
|
||||
# This is a configuration file for apt-cacher-ng, a smart caching proxy for
|
||||
# software package downloads. It's supposed to be in a directory specified by
|
||||
# the -c option of apt-cacher-ng, see apt-cacher-ng(8) for details.
|
||||
# RULES:
|
||||
# - letter case in variable names does not matter
|
||||
# - names and values are separated by colon or equals sign
|
||||
# - for boolean variables, zero means false, non-zero means true
|
||||
# - "default value" means built-in (!) defaults, i.e. something which the
|
||||
# program uses if the option is not set here or in other config files.
|
||||
# That value might be explicitly mentioned in the description. Where it is
|
||||
# not, there is no reason to assume any of the examples to be the default
|
||||
# value! In doubt, use acngtool to query the value of the particular variable.
|
||||
|
||||
# Storage directory for downloaded data and related maintenance activity.
|
||||
#
|
||||
# Note: When the value for CacheDir is changed, change the file
|
||||
# /lib/systemd/system/apt-cacher-ng.service too
|
||||
#
|
||||
CacheDir: {{ apt_cacher_ng__cache_dir }}
|
||||
|
||||
# Log file directory, can be set empty to disable logging
|
||||
#
|
||||
LogDir: {{ apt_cacher_ng__log_dir }}
|
||||
|
||||
# A place to look for additional configuration and resource files if they are not
|
||||
# found in the configuration directory
|
||||
#
|
||||
SupportDir: {{ apt_cacher_ng__support_dir }}
|
||||
|
||||
# TCP server port for incoming http (or HTTP proxy) connections.
|
||||
# Can be set to 9999 to emulate apt-proxy. Value of 0 turns off TCP server
|
||||
# (SocketPath must be set in this case).
|
||||
#
|
||||
Port:{{ apt_cacher_ng__port }}
|
||||
|
||||
# Addresses or hostnames to listen on. Multiple addresses must be separated by
|
||||
# spaces. Each entry must be an exact local address which is associated with a
|
||||
# local interface. DNS resolution is performed using getaddrinfo(3) for all
|
||||
# available protocols (IPv4, IPv6, ...). Using a protocol specific format will
|
||||
# create binding(s) only on protocol specific socket(s), e.g. 0.0.0.0 will
|
||||
# listen only to IPv4. The endpoint can also be specified as host:port (or
|
||||
# [ipv6-address]:port) which allows binding on non-standard ports (Port
|
||||
# directive is ignored in this case).
|
||||
#
|
||||
# Default: listens on all interfaces and protocols
|
||||
#
|
||||
# BindAddress: localhost 192.168.7.254 publicNameOnMainInterface
|
||||
{{ ("BindAddress: " + apt_cacher_ng__bind_address | join(" ")) if apt_cacher_ng__bind_address else "" }}
|
||||
|
||||
# The specification of another HTTP proxy which shall be used for downloads.
|
||||
# It can include user name and password but see the manual for limitations.
|
||||
#
|
||||
# Default: uses direct connection
|
||||
#
|
||||
# Proxy: http://www-proxy.example.net:3128
|
||||
# Proxy: https://username:proxypassword@proxy.example.net:3129
|
||||
{{ ("Proxy: " + apt_cacher_ng__proxy) if apt_cacher_ng__proxy else "" }}
|
||||
|
||||
# Repository remapping. See manual for details.
|
||||
# In this example, some backends files might be generated during package
|
||||
# installation using information collected on the system.
|
||||
# Examples:
|
||||
Remap-debrep: file:deb_mirror*.gz /debian ; file:backends_debian # Debian Archives
|
||||
Remap-uburep: file:ubuntu_mirrors /ubuntu ; file:backends_ubuntu # Ubuntu Archives
|
||||
Remap-klxrep: file:kali_mirrors /kali ; file:backends_kali # Kali Linux Archives
|
||||
Remap-cygwin: file:cygwin_mirrors /cygwin # ; file:backends_cygwin # incomplete, please create this file or specify preferred mirrors here
|
||||
Remap-sfnet: file:sfnet_mirrors # ; file:backends_sfnet # incomplete, please create this file or specify preferred mirrors here
|
||||
Remap-alxrep: file:archlx_mirrors /archlinux # ; file:backend_archlx # Arch Linux
|
||||
Remap-fedora: file:fedora_mirrors # Fedora Linux
|
||||
Remap-epel: file:epel_mirrors # Fedora EPEL
|
||||
Remap-slrep: file:sl_mirrors # Scientific Linux
|
||||
Remap-gentoo: file:gentoo_mirrors.gz /gentoo ; file:backends_gentoo # Gentoo Archives
|
||||
Remap-secdeb: security.debian.org security.debian.org/debian-security deb.debian.org/debian-security /debian-security ; deb.debian.org/debian-security security.debian.org
|
||||
|
||||
# Virtual page accessible in a web browser to see statistics and status
|
||||
# information, i.e. under http://localhost:3142/acng-report.html
|
||||
# NOTE: This option must be configured to run maintenance jobs (even when used
|
||||
# via acngtool in cron scripts). The AdminAuth option can be used to restrict
|
||||
# access to sensitive areas on that page.
|
||||
#
|
||||
# Default: not set, should be set by the system administrator
|
||||
#
|
||||
ReportPage: acng-report.html
|
||||
|
||||
# Socket file for accessing through local UNIX socket instead of TCP/IP. Can be
|
||||
# used with inetd (via bridge tool in.acng from apt-cacher-ng package), is also
|
||||
# used internally for administrative purposes.
|
||||
#
|
||||
# Default: /run/apt-cacher-ng/socket
|
||||
#
|
||||
# SocketPath: /var/run/apt-cacher-ng/socket
|
||||
|
||||
# If set to 1, makes log files be written to disk on every new line. Default
|
||||
# is 0, buffers are flushed after the client disconnects. Technically,
|
||||
# it's a convenience alias for the Debug option, see below for details.
|
||||
#
|
||||
# UnbufferLogs: 0
|
||||
|
||||
# Enables extended client information in log entries. When set to 0, only
|
||||
# activity type, time and transfer sizes are logged.
|
||||
#
|
||||
# VerboseLog: 1
|
||||
VerboseLog: {{ "1" if apt_cacher_ng__verbose_log | bool else "0" }}
|
||||
|
||||
# Don't detach from the starting console.
|
||||
#
|
||||
# ForeGround: 0
|
||||
|
||||
# Store the pid of the daemon process in the specified text file.
|
||||
# Default: disabled
|
||||
#
|
||||
# PidFile: /var/run/apt-cacher-ng/pid
|
||||
|
||||
# Forbid outgoing connections and work without an internet connection or
|
||||
# respond with 503 error where it's not possible.
|
||||
#
|
||||
# Offlinemode: 0
|
||||
Offlinemode: {{ "1" if apt_cacher_ng__offline_mode | bool else "0" }}
|
||||
|
||||
# Forbid downloads from locations that are directly specified in the user
|
||||
# request, i.e. all downloads must be processed by the preconfigured remapping
|
||||
# backends (see above).
|
||||
#
|
||||
# ForceManaged: 0
|
||||
ForceManaged: {{ "1" if apt_cacher_ng__force_managed | bool else "0" }}
|
||||
|
||||
# Days before considering an unreferenced file expired (to be deleted).
|
||||
# WARNING: if the value is set too low and particular index files are not
|
||||
# available for some days (mirror downtime) then there is a risk of removal of
|
||||
# still useful package files.
|
||||
#
|
||||
# ExThreshold: 4
|
||||
{{ ("ExTreshold: " + apt_cacher_ng__expiration_threshold | string) if (apt_cacher_ng__expiration_threshold != "default") else "" }}
|
||||
|
||||
# If the expiration is run daily, it sometimes does not make much sense to do
|
||||
# it because the expected changes (i.e. removal of expired files) don't justify
|
||||
# the extra processing time or additional downloads for expiration operation
|
||||
# itself. This discrepancy might be especially worse if the local client
|
||||
# installations are small or are rarely updated but the daily changes of
|
||||
# the remote archive metadata are heavy.
|
||||
#
|
||||
# The following option enables a possible trade-off: the expiration run is
|
||||
# suppressed until a certain amount of data has been downloaded through
|
||||
# apt-cacher-ng since the last expiration execution (which might indicate that
|
||||
# packages were replaced with newer versions).
|
||||
#
|
||||
# The number can have a suffix (k,K,m,M for Kb,KiB,Mb,MiB)
|
||||
#
|
||||
# ExStartTradeOff: 500m
|
||||
|
||||
# Stop expiration when a critical problem appears, issue like a failed update
|
||||
# of an index file in the preparation step.
|
||||
#
|
||||
# WARNING: don't set this option to zero or empty without considering possible
|
||||
# consequences like a sudden and complete cache data loss.
|
||||
#
|
||||
# ExAbortOnProblems: 1
|
||||
{{ ("ExAbortOnProblems: " + apt_cacher_ng__expiration_abort_on_problems | string) if (apt_cacher_ng__expiration_abort_on_problems != "default") else "" }}
|
||||
|
||||
# Number of failed nightly expiration runs which are considered acceptable and
|
||||
# do not trigger an error notification to the admin (e.g. via daily cron job)
|
||||
# before the (day) count is reached. Might be useful with whacky internet
|
||||
# connections.
|
||||
#
|
||||
# Default: a guessed value, 1 if ExThreshold is 5 or more, 0 otherwise.
|
||||
#
|
||||
# ExSuppressAdminNotification: 1
|
||||
|
||||
# Modify file names to work around limitations of some file systems.
|
||||
# WARNING: experimental feature, subject to change
|
||||
#
|
||||
# StupidFs: 0
|
||||
|
||||
# Experimental feature for apt-listbugs: pass-through SOAP requests and
|
||||
# responses to/from bugs.debian.org.
|
||||
# Default: guessed value, true unless ForceManaged is enabled
|
||||
#
|
||||
# ForwardBtsSoap: 1
|
||||
|
||||
# There is a small in-memory cache for DNS resolution data, expired by
|
||||
# this timeout (in seconds). Internal caching is disabled if set to a value
|
||||
# less than zero.
|
||||
#
|
||||
# DnsCacheSeconds: 1800
|
||||
{{ ("DnsCacheSeconds: " + apt_cacher_ng__dns_cache_seconds | string) if (apt_cacher_ng__dns_cache_seconds != "default") else "" }}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# WARNING: don't modify thread and file matching parameters without a clear
|
||||
# idea of what is happening behind the scene!
|
||||
#
|
||||
# Max. count of connection threads kept ready (for faster response in the
|
||||
# future). Should be a sane value between 0 and average number of connections,
|
||||
# and depend on the amount of spare RAM.
|
||||
# MaxStandbyConThreads: 8
|
||||
#
|
||||
# Hard limit of active thread count for incoming connections, i.e. operation
|
||||
# is refused when this value is reached (below zero = unlimited).
|
||||
# MaxConThreads: -1
|
||||
#
|
||||
# Timeout for a forced disconnect in cases where a client connection is about
|
||||
# to be closed but remote refuses to confirm the disconnect request. Setting
|
||||
# this to a lower value mitigates the effects of resource starvation in case of
|
||||
# a DOS attack but increases the risk of failing to flush the remaining portion
|
||||
# of data.
|
||||
# DisconnectTimeout: 15
|
||||
|
||||
# By default, if a remote suddenly reconnects, ACNG tries at least two times to
|
||||
# redownload from the same or different location (if known).
|
||||
# DlMaxRetries: 2
|
||||
|
||||
# Pigeonholing files (like static vs. volatile contents) is done by (extended)
|
||||
# regular expressions.
|
||||
#
|
||||
# The following patterns are available for the purposes detailed, where
|
||||
# the latter takes precedence over the former:
|
||||
# - «PFilePattern» for static data that doesn't change silently on the server.
|
||||
# - «VFilePattern» for volatile data that may change like every hour. Files
|
||||
# that match both PFilePattern and VfilePattern will be treated as volatile.
|
||||
# - Static data with file names that match VFilePattern may be overridden being
|
||||
# treated as volatile by making it match the special static data pattern,
|
||||
# «SPfilePattern».
|
||||
# - «SVfilePattern» or the "special volatile data" pattern is for the
|
||||
# convenience of specifying any exceptions to matches with SPfilePattern,
|
||||
# for cases where data must still be treated as volatile.
|
||||
# - «WfilePattern» specifies a "whitelist pattern" for the regular expiration
|
||||
# job, telling it to keep the files even if they are not referenced by
|
||||
# others, like crypto signatures with which clients begin their downloads.
|
||||
#
|
||||
# There are two versions. The pattern variables mentioned above should not be
|
||||
# set without good reason, because they would override the built-in defaults
|
||||
# (that might impact updates to future versions of apt-cacher-ng). There are
|
||||
# also versions of those patterns ending with Ex, which may be modified by the
|
||||
# local administrator. They are evaluated in addition to the regular patterns
|
||||
# at runtime.
|
||||
#
|
||||
# To see examples of the expected syntax, run: apt-cacher-ng -p debug=1
|
||||
#
|
||||
# PfilePatternEx:
|
||||
# VfilePatternEx:
|
||||
# SPfilePatternEx:
|
||||
# SVfilePatternEx:
|
||||
# WfilePatternEx:
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# A bitmask type value declaring the logging verbosity and behavior of the error
|
||||
# log writing. Non-zero value triggers at least faster log file flushing.
|
||||
#
|
||||
# Some higher bits only working with a special debug build of apt-cacher-ng,
|
||||
# see the manual for details.
|
||||
#
|
||||
# WARNING: this can write significant amount of data into apt-cacher.err logfile.
|
||||
#
|
||||
# Default: 0
|
||||
#
|
||||
# Debug:3
|
||||
{{ ("Debug: " + apt_cacher_ng__debug | string) if (apt_cacher_ng__debug != "") else "" }}
|
||||
|
||||
# Usually, general purpose proxies like Squid expose the IP address of the
|
||||
# client user to the remote server using the X-Forwarded-For HTTP header. This
|
||||
# behaviour can be optionally turned on with the Expose-Origin option.
|
||||
#
|
||||
# ExposeOrigin: 0
|
||||
|
||||
# When logging the originating IP address, trust the information supplied by
|
||||
# the client in the X-Forwarded-For header.
|
||||
#
|
||||
# LogSubmittedOrigin: 0
|
||||
LogSubmittedOrigin: {{ "1" if apt_cacher_ng__log_submitted_origin | bool else "0" }}
|
||||
|
||||
# The version string reported to the peer, to be displayed as HTTP client (and
|
||||
# version) in the logs of the mirror.
|
||||
#
|
||||
# WARNING: Expect side effects! Some archives use this header to guess
|
||||
# capabilities of the client (i.e. allow redirection and/or https links) and
|
||||
# change their behaviour accordingly but ACNG might not support the expected
|
||||
# features.
|
||||
#
|
||||
# Default:
|
||||
#
|
||||
# UserAgent: Yet Another HTTP Client/1.2.3p4
|
||||
{{ ("UserAgent: " + apt_cacher_ng__user_agent) if (apt_cacher_ng__user_agent != "default") else "" }}
|
||||
|
||||
# In some cases the Import and Expiration tasks might create fresh volatile
|
||||
# data for internal use by reconstructing them using patch files. This
|
||||
# by-product might be recompressed with bzip2 and with some luck the resulting
|
||||
# file becomes identical to the *.bz2 file on the server which can be used by
|
||||
# APT when requesting a complete version of this file.
|
||||
# The downside of this feature is higher CPU load on the server during
|
||||
# the maintenance tasks, and the outcome might have not much value in a LAN
|
||||
# where all clients update their data often and regularly and therefore usually
|
||||
# don't need the full version of the index file.
|
||||
#
|
||||
# RecompBz2: 0
|
||||
RecompBz2: {{ "1" if apt_cacher_ng__recompress_bz2 else "0" }}
|
||||
|
||||
# Network timeout for outgoing connections, in seconds.
|
||||
#
|
||||
# NetworkTimeout: 40
|
||||
{{ ("NetworkTimeout: " + apt_cacher_ng__network_timeout | string) if (apt_cacher_ng__network_timeout != "") else "" }}
|
||||
|
||||
# Fast fallback timeout, in seconds. This is the time to wait before
|
||||
# alternative target addresses for a client connection are tried, which can be
|
||||
# useful for quick fallback to IPv4 in case of whacky IPv6 configuration.
|
||||
#
|
||||
# FastTimeout = 4
|
||||
|
||||
# Sometimes it makes sense to not store the data in cache and just return the
|
||||
# package data to client while it comes in. The following DontCache* parameters
|
||||
# can enable this behaviour for certain URL types. The tokens are extended
|
||||
# regular expressions which the URLs are evaluated against.
|
||||
#
|
||||
# DontCacheRequested is applied to the URL as it comes in from the client.
|
||||
# Example: exclude packages built with kernel-package for x86
|
||||
# DontCacheRequested: linux-.*_10\...\.Custo._i386
|
||||
# Example usecase: exclude popular private IP ranges from caching
|
||||
# DontCacheRequested: 192.168.0 ^10\..* 172.30
|
||||
#
|
||||
# DontCacheResolved is applied to URLs after mapping to the target server. If
|
||||
# multiple backend servers are specified then it's only matched against the
|
||||
# download link for the FIRST possible source (due to implementation limits).
|
||||
#
|
||||
# Example usecase: all Ubuntu stuff comes from a local mirror (specified as
|
||||
# backend), don't cache it again:
|
||||
# DontCacheResolved: ubuntumirror.local.net
|
||||
#
|
||||
# DontCache directive sets (overrides) both, DontCacheResolved and
|
||||
# DontCacheRequested. Provided for convenience, see those directives for
|
||||
# details.
|
||||
#
|
||||
# Example:
|
||||
# DontCache: .*.local.university.int
|
||||
|
||||
# Default permission set of freshly created files and directories, as octal
|
||||
# numbers (see chmod(1) for details).
|
||||
# Can by limited by the umask value (see umask(2) for details) if it's set in
|
||||
# the environment of the starting shell, e.g. in apt-cacher-ng init script or
|
||||
# in its configuration file.
|
||||
#
|
||||
# DirPerms: 00755
|
||||
{{ ("DirPerms: " + apt_cacher_ng__dir_perms) if (apt_cacher_ng__dir_perms != "") else "" }}
|
||||
# FilePerms: 00664
|
||||
{{ ("FilePerms: " + apt_cacher_ng__file_perms) if (apt_cacher_ng__file_perms != "") else "" }}
|
||||
|
||||
# It's possible to use use apt-cacher-ng as a regular web server with a limited
|
||||
# feature set, i.e. directory browsing, downloads of any files, Content-Type
|
||||
# based on /etc/mime.types, but without sorting, CGI execution, index page
|
||||
# redirection and other funny things.
|
||||
# To get this behavior, mappings between virtual directories and real
|
||||
# directories on the server must be defined with the LocalDirs directive.
|
||||
# Virtual and real directories are separated by spaces, multiple pairs are
|
||||
# separated by semi-colons. Real directories must be absolute paths.
|
||||
# NOTE: Since the names of that key directories share the same namespace as
|
||||
# repository names (see Remap-...) it is administrator's job to avoid conflicts
|
||||
# between them or explicitly create them.
|
||||
#
|
||||
# LocalDirs: woo /data/debarchive/woody ; hamm /data/debarchive/hamm
|
||||
LocalDirs: acng-doc /usr/share/doc/apt-cacher-ng
|
||||
|
||||
# Precache a set of files referenced by specified index files. This can be used
|
||||
# to create a partial mirror usable for offline work. There are certain limits
|
||||
# and restrictions on the path specification, see manual and the cache control
|
||||
# web site for details. A list of (maybe) relevant index files could be
|
||||
# retrieved via "apt-get --print-uris update" on a client machine.
|
||||
#
|
||||
# Example:
|
||||
# PrecacheFor: debrep/dists/unstable/*/source/Sources* debrep/dists/unstable/*/binary-amd64/Packages*
|
||||
|
||||
# Arbitrary set of data to append to request headers sent over the wire. Should
|
||||
# be a well formatted HTTP headers part including newlines (DOS style) which
|
||||
# can be entered as escape sequences (\r\n).
|
||||
#
|
||||
# RequestAppendix: X-Tracking-Choice: do-not-track\r\n
|
||||
|
||||
# Specifies the IP protocol families to use for remote connections. Order does
|
||||
# matter, first specified are considered first. Possible combinations:
|
||||
# v6 v4
|
||||
# v4 v6
|
||||
# v6
|
||||
# v4
|
||||
# Default: use native order of the system's TCP/IP stack, influenced by the
|
||||
# BindAddress value.
|
||||
#
|
||||
# ConnectProto: v6 v4
|
||||
{% if apt_cacher_ng__connect_protocol | length >= 1 %}
|
||||
ConnectProto: {{ apt_cacher_ng__connect_protocol | join(" ") }}
|
||||
{% endif %}
|
||||
|
||||
# Regular expiration algorithm finds package files which are no longer listed
|
||||
# in any index file and removes them of them after a safety period.
|
||||
# This option allows to keep more versions of a package in the cache after
|
||||
# the safety period is over.
|
||||
#
|
||||
# KeepExtraVersions: 0
|
||||
|
||||
# Optionally uses TCP access control provided by libwrap, see hosts_access(5)
|
||||
# for details. Daemon name is apt-cacher-ng.
|
||||
#
|
||||
# Default: guessed on startup by looking for explicit mention of apt-cacher-ng
|
||||
# in /etc/hosts.allow or /etc/hosts.deny files.
|
||||
#
|
||||
# UseWrap: 0
|
||||
|
||||
# If many machines from the same local network attempt to update index files
|
||||
# (apt-get update) at nearly the same time, the known state of these index file
|
||||
# is temporarily frozen and multiple requests receive the cached response
|
||||
# without contacting the remote server again. This parameter (in seconds)
|
||||
# specifies the length of this period before these (volatile) files are
|
||||
# considered outdated.
|
||||
# Setting this value too low transfers more data and increases remote server
|
||||
# load, setting this too high (more than a couple of minutes) increases the
|
||||
# risk of delivering inconsistent responses to the clients.
|
||||
#
|
||||
# FreshIndexMaxAge: 27
|
||||
|
||||
# Usually the users are not allowed to specify custom TCP ports of remote
|
||||
# mirrors in the requests, only the default HTTP port can be used (as
|
||||
# workaround, proxy administrator can create Remap- rules with custom ports).
|
||||
# This restriction can be disabled by specifying a list of allowed ports or 0
|
||||
# for any port.
|
||||
#
|
||||
# AllowUserPorts: 80
|
||||
|
||||
# Normally the HTTP redirection responses are forwarded to the original caller
|
||||
# (i.e. APT) which starts a new download attempt from the new URL. This
|
||||
# solution is ok for client configurations with proxy mode but doesn't work
|
||||
# well with configurations using URL prefixes in sources.list. To work around
|
||||
# this the server can restart its own download with a redirection URL,
|
||||
# configured with the following option. The downside is that this might be used
|
||||
# to circumvent download source policies by malicious users.
|
||||
# The RedirMax option specifies how many such redirects the server is allowed
|
||||
# to follow per request, 0 disables the internal redirection.
|
||||
# Default: guessed on startup, 0 if ForceManaged is used and 5 otherwise.
|
||||
#
|
||||
# RedirMax: 5
|
||||
|
||||
# There some broken HTTP servers and proxy servers in the wild which don't
|
||||
# support the If-Range header correctly and return incorrect data when the
|
||||
# contents of a (volatile) file changed. Setting VfileUseRangeOps to zero
|
||||
# disables Range-based requests while retrieving volatile files, using
|
||||
# If-Modified-Since and requesting the complete file instead. Setting it to
|
||||
# a negative value removes even If-Modified-Since headers.
|
||||
#
|
||||
# VfileUseRangeOps: 1
|
||||
|
||||
# Allow data pass-through mode for certain hosts when requested by the client
|
||||
# using a CONNECT request. This is particularly useful to allow access to SSL
|
||||
# sites (https proxying). The string is a regular expression which should cover
|
||||
# the server name with port and must be correctly formatted and terminated.
|
||||
# Examples:
|
||||
# PassThroughPattern: private-ppa\.launchpad\.net:443$
|
||||
# PassThroughPattern: .* # this would allow CONNECT to everything
|
||||
#
|
||||
# Default: ^(bugs\.debian\.org|changelogs\.ubuntu\.com):443$
|
||||
# PassThroughPattern: ^(bugs\.debian\.org|changelogs\.ubuntu\.com):443$
|
||||
|
||||
# It's possible that an evil client requests a volatile file but does not
|
||||
# retrieve the response and keeps the connection effectively stuck over
|
||||
# many hours, blocking the particular file for other download attempts (which
|
||||
# leads to not reporting file changes on server side to other users). In such
|
||||
# case the file descriptor can be moved aside although this might reduce cache
|
||||
# efficiency.
|
||||
#
|
||||
# Default time is based on the value of FreshIndexMaxAge with a safety factor.
|
||||
#
|
||||
# ResponseFreezeDetectTime: 60
|
||||
|
||||
# Keep outgoing connections alive and reuse them for later downloads from
|
||||
# the same server as long as possible.
|
||||
#
|
||||
# ReuseConnections: 1
|
||||
|
||||
# Maximum number of requests sent in a batch to remote servers before the first
|
||||
# response is expected. Using higher values can greatly improve average
|
||||
# throughput depending on network latency and the implementation of remote
|
||||
# servers. Makes most sense when also enabled on the client side, see apt.conf
|
||||
# documentation for details.
|
||||
#
|
||||
# Default: 10 if ReuseConnections is set, 1 otherwise
|
||||
#
|
||||
# PipelineDepth: 10
|
||||
|
||||
# Path to the system directory containing trusted CA certificates used for
|
||||
# outgoing connections, see OpenSSL documentation for details.
|
||||
#
|
||||
# CApath: /etc/ssl/certs
|
||||
#
|
||||
# Path to a single trusted trusted CA certificate used for outgoing
|
||||
# connections, see OpenSSL documentation for details.
|
||||
#
|
||||
# CAfile:
|
||||
|
||||
# There are different ways to detect that an upstream proxy is broken and turn
|
||||
# off its use and connect directly. The first is through a custom command -
|
||||
# when it returns successfully, the proxy is used, otherwise not and the
|
||||
# command will be rerun only after a specified period.
|
||||
# Another way is to try to connect to the proxy first and detect a connection
|
||||
# timeout. The connection will then be made without HTTP proxy for the life
|
||||
# time of the particular download stream and it may also affect other other
|
||||
# parallel downloads.
|
||||
# NOTE: this operation modes are still experimental and are subject to change!
|
||||
# Unwanted side effects may occur with multiple simultaneous user connections
|
||||
# or with specific per-repository proxy settings.
|
||||
#
|
||||
# Shell command, default: not set. Executed with the default shell and
|
||||
# permissions of the apt-cacher-ng's process user. Examples:
|
||||
# /bin/ip route | grep -q 192.168.117
|
||||
# /usr/sbin/arp | grep -q 00:22:1f:51:8e:c1
|
||||
#
|
||||
# OptProxyCheckCommand: ...
|
||||
#
|
||||
# Check interval, in seconds.
|
||||
#
|
||||
# OptProxyCheckInterval: 99
|
||||
#
|
||||
# Connection timeout in seconds, default: negative, means disabled.
|
||||
#
|
||||
# OptProxyTimeout: -1
|
||||
|
||||
# It's possible to limit the processing speed of download agents to set an
|
||||
# overall download speed limit. Unit: KiB/s, Default: unlimited.
|
||||
#
|
||||
# MaxDlSpeed: 500
|
||||
{{ ("MaxDlSpeed: " + apt_cacher_ng__max_download_speed_kib | string) if (apt_cacher_ng__max_download_speed_kib != "") else "" }}
|
||||
|
||||
# In special corner cases, download clients attempt to download random chunks
|
||||
# of a files headers, i.e. the first kilobytes. The "don't get client stuck"
|
||||
# policy converts this usually to a 200 response starting the body from the
|
||||
# beginning but that confuses some clients. When this option is set to a
|
||||
# certain value, this modifies the behaviour and allows to start a file
|
||||
# download where the distance between available data and the specified range
|
||||
# lies within that bounds. This can look like random lag for the user but
|
||||
# should be harmless apart from that.
|
||||
#
|
||||
# MaxInresponsiveDlSize: 64000
|
||||
|
||||
# In mobile environments having an adhoc connection with a redirection to some
|
||||
# id verification side, this redirect might damage the cache since the data is
|
||||
# involuntarily stored as package data. There is a mechanism which attempts to
|
||||
# detect a such situation and mitigate the mentioned effects by not storing the
|
||||
# data and also dropping the DNS cache. The trigger is the occurrence of a
|
||||
# specific SUBSTRING in the content type field of the final download target
|
||||
# (i.e. the auth web site) and at least one followed redirection.
|
||||
#
|
||||
# BadRedirDetectMime: text/html
|
||||
|
||||
# When a BUS signal is received (typically on IO errors), a shell command can be
|
||||
# executed before the daemon is terminated.
|
||||
# Example:
|
||||
# BusAction: ls -l /proc/$PPID/ | mail -s SIGBUS! root
|
||||
|
||||
# Only set this value for debugging purposes. It disables SSL security checks
|
||||
# like strict host verification. 0 means no, any other value can have
|
||||
# different meaning in the future.
|
||||
#
|
||||
# NoSSLChecks: 0
|
||||
|
||||
# Setting this value means: on file downloads from/via cache, tag relevant
|
||||
# files. And when acngtool runs the shrink command, it will look at the day
|
||||
# when the file was retrieved from cache last time (and not when it was
|
||||
# originally downloaded).
|
||||
#
|
||||
# TrackFileUse: 0
|
||||
|
||||
# Controls preallocation of file system space where this feature is supported.
|
||||
# This might reduce disk fragmentation and therefore improve later read
|
||||
# performance. However, write performance can be reduced which could be
|
||||
# exploited by malicious users.
|
||||
# The value defines a size limit of how much to report to the OS as expected
|
||||
# file size (starting from the beginning of the file).
|
||||
# Set to zero to disable this feature completely. Default: one megabyte
|
||||
#
|
||||
# ReserveSpace: 1048576
|
||||
|
||||
{{ apt_cacher_ng__custom }}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{{ apt_cacher_ng__upstream_mirror_debian }}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{{ apt_cacher_ng__upstream_mirror_gentoo }}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{{ apt_cacher_ng__upstream_mirror_ubuntu }}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# This file contains confidential data and should be protected with file
|
||||
# permissions from being read by untrusted users.
|
||||
#
|
||||
# NOTE: permissions are fixated with dpkg-statoverride on Debian systems.
|
||||
# Read its manual page for details.
|
||||
|
||||
# Basic authentication with username and password, required to
|
||||
# visit pages with administrative functionality. Format: username:password
|
||||
|
||||
AdminAuth: {{ apt_cacher_ng__user | default('admin') }}:{{ apt_cacher_ng__password | default('password') }}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
{# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=8" />
|
||||
<meta name="MSSmartTagsPreventParsing" content="true" />
|
||||
<title>Not Found or APT Reconfiguration required</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<table border=0 cellspacing=0 cellpadding=0 width=580 class="center">
|
||||
<tr>
|
||||
<td class="title" style="width:580px;">The requested page is not accessible.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="visarea" style="width:580px;text-align:left;"><br>
|
||||
You attempted to browse the contents of a virtual HTTP repository.
|
||||
However, the intended way of use is the configuration of APT and
|
||||
related package management systems to retrieve the software packages
|
||||
through this service.
|
||||
<p>To configure APT for use of Apt-Cacher NG you need to...
|
||||
<br>
|
||||
<ul>
|
||||
<li>
|
||||
<b>EITHER:</b> Configure APT to use a HTTP proxy by specifying
|
||||
it in apt.conf or related configuration files, see
|
||||
apt.conf manual page for details. Server and Port need to match
|
||||
the values used to visit this page. For example,
|
||||
edit <i>/etc/apt/apt.conf</i> (or create a new file called like <i>/etc/apt/apt.conf.d/00aptproxy</i>) and add the line:
|
||||
<p />
|
||||
<div class="rawstyle">Acquire::http::Proxy "http://{{ apt_cacher_ng__fqdn }}";</div>
|
||||
<p />
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>OR:</b>
|
||||
Edit the <i>/etc/apt/sources.list</i> file and edit the source lines
|
||||
therein, replacing the mirror hostname with the hostname of this
|
||||
server machine. For example:
|
||||
<p /><div class="rawstyle" style="color:gray;">
|
||||
deb http://ftp.debian.org/debian stable main contrib non-free<br>
|
||||
deb-src http://ftp.debian.org/debian stable main contrib non-free<br>
|
||||
deb https://get.docker.com/ubuntu docker main<br></div><p/>
|
||||
becomes:<p/>
|
||||
<div class="rawstyle">deb http://<span style="color:red">{{ apt_cacher_ng__fqdn }}/</span>ftp.debian.org/debian stable main contrib non-free<br/>
|
||||
deb-src http://<span style="color:red">{{ apt_cacher_ng__fqdn }}/</span>ftp.debian.org/debian stable main contrib non-free<br/>
|
||||
deb <span style="color:red">http://{{ apt_cacher_ng__fqdn }}//HTTPS///</span>get.docker.com/ubuntu docker main</div><p/>
|
||||
Depending on the configuration, it might be possible to use a shortcut
|
||||
for the base URLs without knowing the mirror, for example:<p/>
|
||||
<div class="rawstyle">deb http://{{ apt_cacher_ng__fqdn }}/debian stable main contrib non-free</div><p/>
|
||||
Ask your system administrator for details.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Related links</h3>
|
||||
<ul>
|
||||
<li><a href="${cfg:ReportPage}">Statistics report and configuration page</a> for this Apt-Cacher NG installation</li>
|
||||
<li><a href="https://www.unix-ag.uni-kl.de/~bloch/acng/">Project Homepage</a>
|
||||
</ul>
|
||||
|
||||
${footer}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. envvar:: apt_cacher_ng__apparmor__tunables_dependent
|
||||
#
|
||||
# Configuration for the ``debops-contrib.apparmor`` role.
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# apt_cacher_ng__apparmor__tunables_dependent: '@{APT_CACHE_DIR}+={{ apt_cacher_ng__cache_dir }}'
|
||||
#
|
||||
# Does not work. Error is: Variable was previously declared. Not sure if this is supposed to work?
|
||||
# ``apt_cacher_ng__apparmor__dependent_config`` works without issues.
|
||||
apt_cacher_ng__apparmor__tunables_dependent: ''
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
debops.apt_install - Manage APT packages using Ansible
|
||||
|
||||
Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,435 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_install__ref_defaults:
|
||||
|
||||
# debops.apt_install default variables [[[
|
||||
# ========================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# Role configuration [[[
|
||||
# ----------------------
|
||||
|
||||
# .. envvar:: apt_install__enabled [[[
|
||||
#
|
||||
# Enable or disable support for ``debops.apt_install`` role.
|
||||
apt_install__enabled: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__distribution [[[
|
||||
#
|
||||
# The variable that indicates host operating system distribution, used to
|
||||
# conditionally select packages for installation.
|
||||
apt_install__distribution: '{{ ansible_local.core.distribution
|
||||
| d(ansible_lsb.id | d(ansible_distribution)) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__distribution_release [[[
|
||||
#
|
||||
# The variable that indicates host distribution release, used to conditionally
|
||||
# select packages for installation.
|
||||
apt_install__distribution_release: '{{ ansible_local.core.distribution_release
|
||||
| d(ansible_lsb.codename | d(ansible_distribution_release)) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__archive_areas_map [[[
|
||||
#
|
||||
# A dictionary that maps different parts of the package archive to each
|
||||
# distribution. By default the role expects all of the archives to be enabled.
|
||||
apt_install__archive_areas_map:
|
||||
'Debian': [ 'main', 'contrib', 'non-free' ]
|
||||
'Ubuntu': [ 'main', 'restricted', 'universe', 'multiverse' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__archive_areas [[[
|
||||
#
|
||||
# List of package archive areas which are currently available. This list is
|
||||
# used to conditionally enable packages for installation, depending on
|
||||
# availability of a given archive area.
|
||||
apt_install__archive_areas: '{{ ansible_local.apt.components
|
||||
| d(apt_install__archive_areas_map[apt_install__distribution] | d([])) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__condition_map [[[
|
||||
#
|
||||
# Definition of the values to compare :ref:`apt_install__all_packages` against.
|
||||
# This map is used internally in the :envvar:`apt_install__all_packages` lookup
|
||||
# template.
|
||||
apt_install__condition_map:
|
||||
'distribution': '{{ apt_install__distribution }}'
|
||||
'release': '{{ apt_install__distribution_release }}'
|
||||
'areas': '{{ apt_install__archive_areas }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__state [[[
|
||||
#
|
||||
# How the :command:`apt` Ansible module should install the selected packages:
|
||||
#
|
||||
# ``present``
|
||||
# Only make sure that the packages on the list are present on the host.
|
||||
#
|
||||
# ``latest``
|
||||
# Install the latest version of available packages, according to APT
|
||||
# preferences.
|
||||
#
|
||||
# By default role will make sure to update the packages to their latest version
|
||||
# on first run, and just keep the current version on subsequent runs.
|
||||
apt_install__state: '{{ "present"
|
||||
if (ansible_local | d() and ansible_local.apt_install | d() and
|
||||
(ansible_local.apt_install.configured | d(True)) | bool)
|
||||
else "latest" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__no_kernel_hints [[[
|
||||
#
|
||||
# Enable or disable configuration of the hints about upgraded kernel requiring
|
||||
# a reboot of the host, created by the :command:`needrestart` package. By
|
||||
# default these hints will be disabled, which helps with non-interactive APT
|
||||
# package installation done by Ansible.
|
||||
apt_install__no_kernel_hints: '{{ True
|
||||
if ("needrestart" in apt_install__conditional_whitelist_packages)
|
||||
else False }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__recommends [[[
|
||||
#
|
||||
# Boolean variable that controls installation of recommended packages.
|
||||
apt_install__recommends: False
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__update_cache [[[
|
||||
#
|
||||
# Enable or disable APT cache updates.
|
||||
apt_install__update_cache: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__cache_valid_time [[[
|
||||
#
|
||||
# Amount of time between APT cache updates in seconds.
|
||||
apt_install__cache_valid_time: '{{ ansible_local.core.cache_valid_time | d(60 * 60 * 24 * 7) }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Debconf package configuration [[[
|
||||
# --------------------------------
|
||||
|
||||
# These lists can be used to insert new values into the debconf database. This
|
||||
# allow to overwrite some default answer before installing a package and avoid
|
||||
# using ``dpkg-reconfigure`` to set the wanted answer.
|
||||
# See :ref:`apt_install__ref_debconf` for more details.
|
||||
|
||||
# .. envvar:: apt_install__debconf [[[
|
||||
#
|
||||
# List of values to configure for all hosts in the Ansible inventory.
|
||||
apt_install__debconf: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__group_debconf [[[
|
||||
#
|
||||
# List of values to configure for hosts in specific Ansible
|
||||
# inventory group.
|
||||
apt_install__group_debconf: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__host_debconf [[[
|
||||
#
|
||||
# List of values to configure for specific hosts in the Ansible
|
||||
# inventory.
|
||||
apt_install__host_debconf: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT package lists [[[
|
||||
# ---------------------
|
||||
|
||||
# The APT packages to install are split into multiple lists to easier
|
||||
# modification. You can specify name of each package directly or use a YAML
|
||||
# dictionary to better control when a package should be installed. See
|
||||
# :ref:`apt_install__all_packages` for more details.
|
||||
|
||||
# .. envvar:: apt_install__base_packages [[[
|
||||
#
|
||||
# Default base packages to install.
|
||||
apt_install__base_packages:
|
||||
- 'ed'
|
||||
- 'lsb-release'
|
||||
- 'make'
|
||||
- 'git'
|
||||
- 'curl'
|
||||
- 'rsync'
|
||||
- 'bsdutils'
|
||||
- 'acl'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__shell_packages [[[
|
||||
#
|
||||
# Command line creature comforts, when you need to login to the remote host.
|
||||
apt_install__shell_packages:
|
||||
- 'ncurses-term'
|
||||
- 'tmux'
|
||||
- 'less'
|
||||
- 'file'
|
||||
- 'psmisc'
|
||||
- 'lsof'
|
||||
- 'tree'
|
||||
- 'htop'
|
||||
- 'iftop'
|
||||
- 'nload'
|
||||
- 'nmon'
|
||||
- 'mtr-tiny'
|
||||
- 'mc'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__editor_packages [[[
|
||||
#
|
||||
# List of text editors to install.
|
||||
apt_install__editor_packages:
|
||||
|
||||
# The role also sets ``vim.basic`` as the default editor via
|
||||
# the :envvar:`apt_install__default_alternatives` variable.
|
||||
# If you change this list, remember to update that variable as well,
|
||||
# otherwise the playbook execution will break.
|
||||
- 'vim'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__packages [[[
|
||||
#
|
||||
# List of APT packages to install on all hosts in Ansible inventory.
|
||||
apt_install__packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__group_packages [[[
|
||||
#
|
||||
# List of APT packages to install on hosts in a specific group in Ansible
|
||||
# inventory.
|
||||
apt_install__group_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__host_packages [[[
|
||||
#
|
||||
# List of APT packages to install on specific hosts in Ansible inventory.
|
||||
apt_install__host_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__dependent_packages [[[
|
||||
#
|
||||
# List of APT packages to install for other Ansible roles, for usage as
|
||||
# a dependent role.
|
||||
apt_install__dependent_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__conditional_whitelist_packages [[[
|
||||
#
|
||||
# List of APT package names which will be used to compare against packages
|
||||
# requested for installation. This list is exposed in the defaults so that you
|
||||
# don't need to modify the conditional list below to enable or disable
|
||||
# packages.
|
||||
apt_install__conditional_whitelist_packages:
|
||||
- 'irqbalance'
|
||||
- 'uptimed'
|
||||
- 'libpam-systemd'
|
||||
- 'haveged'
|
||||
- 'gnupg-curl'
|
||||
- 'needrestart'
|
||||
- 'open-vm-tools'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__conditional_packages [[[
|
||||
#
|
||||
# List of APT packages installed under certain conditions.
|
||||
apt_install__conditional_packages:
|
||||
|
||||
- name: 'irqbalance'
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present"
|
||||
if (ansible_processor_cores >= 2 and
|
||||
(ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"]))
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'uptimed'
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present"
|
||||
if (ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"])
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'libpam-systemd'
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present" if (ansible_service_mgr == "systemd") else "absent" }}'
|
||||
|
||||
- name: 'haveged'
|
||||
# KVM is capable of providing entropy to guests however this needs to be
|
||||
# configured on the hypervisor host and thus can not always be done if one
|
||||
# only controls a guest.
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present"
|
||||
if (ansible_virtualization_role | d("guest") in ["guest"] and
|
||||
ansible_virtualization_type | d("unknown") not in ["lxc", "openvz"] and
|
||||
not (ansible_local | d() and ansible_local.apt_install | d() and
|
||||
ansible_local.apt_install.have_virtual_rng | d(False) | bool))
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'gnupg-curl'
|
||||
# This package is needed when you want to access HKPS keyservers.
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present"
|
||||
if ansible_distribution_release in
|
||||
["trusty", "xenial"]
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'needrestart'
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: 'present'
|
||||
|
||||
- name: 'open-vm-tools'
|
||||
whitelist: '{{ apt_install__conditional_whitelist_packages }}'
|
||||
state: '{{ "present"
|
||||
if (ansible_virtualization_role | d("guest") in ["guest"] and
|
||||
ansible_virtualization_type | d("unknown") in ["VMware"])
|
||||
else "absent" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__firmware_packages [[[
|
||||
#
|
||||
# Certain systems require free or non-free firmware for correct operation. This
|
||||
# list of packages will ensure that the required firmware is installed.
|
||||
apt_install__firmware_packages:
|
||||
|
||||
- name: 'amd64-microcode'
|
||||
# Non-free microcode firmware for AMD CPUs. These patches mitigate security
|
||||
# issues like Spectre and fix other types of incorrect processor behaviour.
|
||||
# The package only needs to be installed on physical machines. To protect
|
||||
# virtual machines, be sure to set the correct CPU flags in QEMU:
|
||||
# https://www.qemu.org/docs/master/system/target-i386.html#important-cpu-features-for-intel-x86-hosts
|
||||
distribution: [ 'Debian', 'Devuan', 'Ubuntu' ]
|
||||
areas: '{{ ["main"]
|
||||
if ansible_distribution in ["Ubuntu"]
|
||||
else ["non-free"] }}'
|
||||
state: '{{ "present"
|
||||
if ansible_virtualization_role == "host" and
|
||||
"AuthenticAMD" in ansible_processor
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'firmware-linux-free'
|
||||
distribution: [ 'Debian' ]
|
||||
state: '{{ "present" if (ansible_form_factor in ["Rack Mount Chassis"])
|
||||
and (ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"])
|
||||
and (ansible_kernel.find("-pve") == "-1")
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'firmware-linux-nonfree'
|
||||
distribution: [ 'Debian' ]
|
||||
areas: [ 'non-free' ]
|
||||
state: '{{ "present" if (ansible_form_factor in ["Rack Mount Chassis"])
|
||||
and (ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"])
|
||||
and (ansible_kernel.find("-pve") == "-1")
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'intel-microcode'
|
||||
# Same as amd64-microcode, but for Intel CPUs.
|
||||
distribution: [ 'Debian', 'Devuan', 'Ubuntu' ]
|
||||
areas: '{{ ["main"]
|
||||
if ansible_distribution in ["Ubuntu"]
|
||||
else ["non-free"] }}'
|
||||
state: '{{ "present" if ansible_virtualization_role == "host" and
|
||||
"GenuineIntel" in ansible_processor
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'linux-firmware'
|
||||
distribution: [ 'Ubuntu' ]
|
||||
state: '{{ "present" if (ansible_form_factor in ["Rack Mount Chassis"])
|
||||
and (ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"])
|
||||
else "absent" }}'
|
||||
|
||||
- name: 'linux-firmware-nonfree'
|
||||
distribution: [ 'Ubuntu' ]
|
||||
release: [ 'precise', 'trusty', 'wily' ]
|
||||
areas: [ 'multiverse' ]
|
||||
state: '{{ "present" if (ansible_form_factor in ["Rack Mount Chassis"])
|
||||
and (ansible_virtualization_role is undefined or
|
||||
ansible_virtualization_role not in ["guest"])
|
||||
else "absent" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__all_packages [[[
|
||||
#
|
||||
# The master list of APT packages to install, passed to the lookup template for
|
||||
# conditional processing.
|
||||
apt_install__all_packages:
|
||||
- '{{ apt_install__base_packages }}'
|
||||
- '{{ apt_install__shell_packages }}'
|
||||
- '{{ apt_install__editor_packages }}'
|
||||
- '{{ apt_install__packages }}'
|
||||
- '{{ apt_install__group_packages }}'
|
||||
- '{{ apt_install__host_packages }}'
|
||||
- '{{ apt_install__dependent_packages }}'
|
||||
- '{{ apt_install__conditional_packages }}'
|
||||
- '{{ apt_install__firmware_packages }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Alternative package symlinks [[[
|
||||
# --------------------------------
|
||||
|
||||
# These lists can be used to define alternative symlinks for certain packages
|
||||
# which provide similar functionality, using ``update-alternatives`` package.
|
||||
# See :ref:`apt_install__ref_alternatives` for more details.
|
||||
|
||||
# .. envvar:: apt_install__default_alternatives [[[
|
||||
#
|
||||
# List of default alternative symlinks set by the role.
|
||||
apt_install__default_alternatives:
|
||||
|
||||
# The role also installs the ``vim`` package via the
|
||||
# :envvar:`apt_install__editor_packages` variable.
|
||||
- name: 'editor'
|
||||
path: '/usr/bin/vim.basic'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__alternatives [[[
|
||||
#
|
||||
# List of alternative symlinks configured for all packages in the Ansible
|
||||
# inventory.
|
||||
apt_install__alternatives: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__group_alternatives [[[
|
||||
#
|
||||
# List of alternative symlinks configured for hosts in specific Ansible
|
||||
# inventory group.
|
||||
apt_install__group_alternatives: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_install__host_alternatives [[[
|
||||
#
|
||||
# List of alternative symlinks configured for specific hosts in the Ansible
|
||||
# inventory.
|
||||
apt_install__host_alternatives: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Configuration for other Ansible roles [[[
|
||||
# -----------------------------------------
|
||||
|
||||
# .. envvar:: apt_install__apt_preferences__dependent_list [[[
|
||||
#
|
||||
# Configuration for the :ref:`debops.apt_preferences` role.
|
||||
apt_install__apt_preferences__dependent_list:
|
||||
|
||||
- package: 'needrestart needrestart-*'
|
||||
backports: [ 'trusty' ]
|
||||
reason: 'Better support for container technologies'
|
||||
by_role: 'debops.apt_install'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski, Robin Schneider'
|
||||
description: 'Install APT packages on Debian and other compatible systems'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.0.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- apt
|
||||
- packages
|
||||
- packaging
|
||||
- deployment
|
||||
- software
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import custom Ansible plugins
|
||||
ansible.builtin.import_role:
|
||||
name: 'ansible_plugins'
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Import DebOps secret role
|
||||
ansible.builtin.import_role:
|
||||
name: 'secret'
|
||||
|
||||
- name: Pre hooks
|
||||
ansible.builtin.include_tasks: '{{ lookup("debops.debops.task_src", "apt_install/pre_main.yml") }}'
|
||||
|
||||
- name: Make sure that Ansible fact directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
when: apt_install__enabled | bool
|
||||
|
||||
- name: Save local Ansible facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apt_install.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apt_install.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
when: apt_install__enabled | bool
|
||||
notify: [ 'Refresh host facts' ]
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Update Ansible facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
||||
- name: Debconf module dependencies
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- 'debconf'
|
||||
- 'debconf-utils'
|
||||
state: 'present'
|
||||
install_recommends: '{{ apt_install__recommends | bool }}'
|
||||
register: apt_install__register_debconf_packages
|
||||
until: apt_install__register_debconf_packages is succeeded
|
||||
|
||||
- name: Apply requested packages configuration
|
||||
ansible.builtin.debconf:
|
||||
name: '{{ item.name }}'
|
||||
question: '{{ item.question | d(omit) }}'
|
||||
selection: '{{ item.selection | d(omit) }}'
|
||||
setting: '{{ item.setting | d(omit) }}'
|
||||
unseen: '{{ item.unseen | d(omit) }}'
|
||||
value: '{{ item.value | d(omit) }}'
|
||||
answer: '{{ item.answer | d(omit) }}'
|
||||
vtype: '{{ item.vtype | d(omit) }}'
|
||||
loop: '{{ q("flattened", apt_install__debconf
|
||||
+ apt_install__group_debconf
|
||||
+ apt_install__host_debconf) }}'
|
||||
when: item.name | d()
|
||||
|
||||
- name: Install requested APT packages
|
||||
ansible.builtin.apt:
|
||||
name: '{{ q("flattened", lookup("template",
|
||||
"lookup/apt_install__all_packages.j2",
|
||||
convert_data=False) | from_yaml) }}'
|
||||
state: '{{ apt_install__state }}'
|
||||
install_recommends: '{{ apt_install__recommends | bool }}'
|
||||
update_cache: '{{ apt_install__update_cache | bool }}'
|
||||
cache_valid_time: '{{ apt_install__cache_valid_time }}'
|
||||
register: apt_install__register_packages
|
||||
until: apt_install__register_packages is succeeded
|
||||
when: apt_install__enabled | bool
|
||||
|
||||
- name: Configure alternative symlinks
|
||||
community.general.alternatives:
|
||||
name: '{{ item.name }}'
|
||||
path: '{{ item.path }}'
|
||||
link: '{{ item.link | d(omit) }}'
|
||||
priority: '{{ item.priority | d(omit) }}'
|
||||
loop: '{{ q("flattened", apt_install__default_alternatives
|
||||
+ apt_install__alternatives
|
||||
+ apt_install__group_alternatives
|
||||
+ apt_install__host_alternatives) }}'
|
||||
when: item.name | d() and item.path | d()
|
||||
|
||||
- name: Configure automatic alternatives
|
||||
ansible.builtin.command: update-alternatives --auto {{ item.name }}
|
||||
register: apt_install__register_alternatives
|
||||
loop: '{{ q("flattened", apt_install__alternatives
|
||||
+ apt_install__group_alternatives
|
||||
+ apt_install__host_alternatives) }}'
|
||||
when: item.name | d() and not item.path | d()
|
||||
changed_when: apt_install__register_alternatives.stdout | d()
|
||||
|
||||
- name: Disable kernel hints about pending upgrades
|
||||
ansible.builtin.template:
|
||||
src: 'etc/needrestart/conf.d/no-kernel-hints.conf.j2'
|
||||
dest: '/etc/needrestart/conf.d/no-kernel-hints.conf'
|
||||
mode: '0644'
|
||||
when: apt_install__enabled | bool and apt_install__no_kernel_hints | bool
|
||||
|
||||
- name: Post hooks
|
||||
ansible.builtin.include_tasks: '{{ lookup("debops.debops.task_src", "apt_install/post_main.yml") }}'
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2022 David Härdeman <david@hardeman.nu>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
import os
|
||||
|
||||
|
||||
def dir_exists(path):
|
||||
return os.path.isdir(path)
|
||||
|
||||
|
||||
def module_loaded(mod):
|
||||
return dir_exists(os.path.join('/sys/module', mod))
|
||||
|
||||
|
||||
output = {
|
||||
'configured': True,
|
||||
'have_virtual_rng': module_loaded('virtio_rng')
|
||||
}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Kernel upgrade hints are disabled to allow for non-interactive APT package
|
||||
# installs. Without this, non-interactive APT operations, for example performed
|
||||
# by Ansible, will hang indefinitely - waiting for user interaction.
|
||||
$nrconf{kernelhints} = 0;
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
{# Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
{% macro get_yaml_list_from_string_or_list(package_map, item) %}{# ((( #}
|
||||
{{ ([ package_map[item] ]
|
||||
if (package_map[item] is string)
|
||||
else (package_map[item] | list)) | to_yaml }}
|
||||
{% endmacro %}{# ))) #}
|
||||
{% macro process_packages(packages, apt_install__tpl_package_list) %}{# ((( #}
|
||||
{% for element in packages %}
|
||||
{% if element is string %}
|
||||
{% set _ = apt_install__tpl_package_list.append(element) %}
|
||||
{% elif element is mapping %}
|
||||
{% if element.state | d('present') == 'present' and element.name | d() %}
|
||||
{% set apt_install__tpl_to_meet_condition_list = apt_install__condition_map.keys() %}
|
||||
{% set apt_install__tpl_met_condition_list = [] %}
|
||||
{% for condition_name_to_meet in apt_install__tpl_to_meet_condition_list %}
|
||||
{% if element[condition_name_to_meet] is defined %}
|
||||
{% for condition_item_to_meet in get_yaml_list_from_string_or_list(element, condition_name_to_meet) | from_yaml | map('lower') %}
|
||||
{% if condition_item_to_meet in (get_yaml_list_from_string_or_list(apt_install__condition_map, condition_name_to_meet) | from_yaml | map('lower')) %}
|
||||
{% set _ = apt_install__tpl_met_condition_list.append(condition_name_to_meet) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% set _ = apt_install__tpl_met_condition_list.append(condition_name_to_meet) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if (apt_install__tpl_met_condition_list | unique | length) == (apt_install__tpl_to_meet_condition_list | unique | length) %}
|
||||
{% set _ = apt_install__tpl_package_list.append(get_yaml_list_from_string_or_list(element, 'name') | from_yaml
|
||||
| intersect(element.whitelist | d(get_yaml_list_from_string_or_list(element, 'name') | from_yaml)) | list) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% for things in element %}
|
||||
{% set _ = process_packages(things, apt_install__tpl_package_list) %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}{# ))) #}
|
||||
|
||||
{% set apt_install__tpl_package_list = [] %}
|
||||
{% for elements in apt_install__all_packages %}
|
||||
{% set _ = process_packages(elements, apt_install__tpl_package_list) %}
|
||||
{% endfor %}
|
||||
{{ [ apt_install__tpl_package_list ] | to_nice_yaml }}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
debops.apt_listchanges - Manage apt-listchanges using Ansible
|
||||
|
||||
Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2016 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2016 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_listchanges__ref_defaults:
|
||||
|
||||
# debops.apt_listchanges default variables [[[
|
||||
# ============================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# APT package and installation [[[
|
||||
# --------------------------------
|
||||
|
||||
# .. envvar:: apt_listchanges__deploy_state [[[
|
||||
#
|
||||
# Specify if the :command:`apt-listchanges` package should be installed (``present``)
|
||||
# or not installed (``absent``). All specified packages will be purged if the
|
||||
# role is disabled using this variable.
|
||||
apt_listchanges__deploy_state: 'present'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__base_packages [[[
|
||||
#
|
||||
# List of APT packages to install.
|
||||
apt_listchanges__base_packages: [ 'apt-listchanges' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__packages [[[
|
||||
#
|
||||
# List of additional APT packages to install with :command:`apt-listpackages`.
|
||||
apt_listchanges__packages: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Main configuration options [[[
|
||||
# ------------------------------
|
||||
|
||||
# .. envvar:: apt_listchanges__mail_to [[[
|
||||
#
|
||||
# List of e-mail accounts to which messages from :command:`apt-listchanges` will be
|
||||
# sent.
|
||||
apt_listchanges__mail_to: '{{ ansible_local.core.admin_private_email | d(["root"]) }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__apt_frontend [[[
|
||||
#
|
||||
# Specify which :command:`apt-listchanges` frontend to use when the script is executed
|
||||
# by APT operations. By default the frontend is ``mail`` unless ``apticron`` is
|
||||
# detected in which case the APT frontend is disabled, since ``apticron`` will
|
||||
# send virtually the same e-mails anyway.
|
||||
#
|
||||
# See :command:`apt-listchanges(1)` for list of available frontends.
|
||||
apt_listchanges__apt_frontend: '{{ "none"
|
||||
if (ansible_local | d() and ansible_local.apticron | d() and
|
||||
ansible_local.apticron.enabled | bool)
|
||||
else (ansible_local.apt_listchanges.apt.frontend
|
||||
if (ansible_local.apt_listchanges.apt | d() and
|
||||
ansible_local.apt_listchanges.apt.frontend | d())
|
||||
else "mail") }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__apt_which [[[
|
||||
#
|
||||
# Specify what information should be sent when the script is run by APT
|
||||
# operations. Choices: ``news``, ``changelogs``, ``both``. By default only
|
||||
# important NEWS items will be sent.
|
||||
apt_listchanges__apt_which: 'news'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__apticron_frontend [[[
|
||||
#
|
||||
# Specify what frontend to use when the script is executed by ``apticron``. See
|
||||
# :command:`apt-listchanges(1)` for information about available frontends.
|
||||
apt_listchanges__apticron_frontend: 'mail'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__apticron_which [[[
|
||||
#
|
||||
# Specify what information should be sent when the script is run by
|
||||
# ``apticron``. Choices: ``news``, ``changelogs``, ``both``.
|
||||
apt_listchanges__apticron_which: 'both'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Configuration profiles [[[
|
||||
# --------------------------
|
||||
|
||||
# .. envvar:: apt_listchanges__profiles [[[
|
||||
#
|
||||
# YAML dictionary with information about :command:`apt-listchanges` profiles which
|
||||
# should be configured. Each value should be a YAML dictionary with key: value
|
||||
# pairs which define the configuration options. See :command:`apt-listchanges(1)` for
|
||||
# information about what options can be configured in a profile.
|
||||
apt_listchanges__profiles:
|
||||
'cmdline': '{{ apt_listchanges__profile_cmdline }}'
|
||||
'apt': '{{ apt_listchanges__profile_apt }}'
|
||||
'apticron': '{{ apt_listchanges__profile_apticron }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__profile_cmdline [[[
|
||||
#
|
||||
# Profile used when :command:`apt-listchanges` is run from the command line, according
|
||||
# th the manual.
|
||||
apt_listchanges__profile_cmdline:
|
||||
frontend: 'pager'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__profile_apt [[[
|
||||
#
|
||||
# Profile used when :command:`apt-listchanges` is executed during APT operations.
|
||||
apt_listchanges__profile_apt:
|
||||
frontend: '{{ apt_listchanges__apt_frontend }}'
|
||||
email_address: '{{ apt_listchanges__mail_to | join(",") }}'
|
||||
confirm: '0'
|
||||
which: '{{ apt_listchanges__apt_which }}'
|
||||
save_seen: '/var/lib/apt/listchanges.db'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_listchanges__profile_apticron [[[
|
||||
#
|
||||
# Profile used when :command:`apt-listchanges` is run by ``apticron``.
|
||||
apt_listchanges__profile_apticron:
|
||||
frontend: '{{ apt_listchanges__apticron_frontend }}'
|
||||
email_address: '{{ apt_listchanges__mail_to | join(",") }}'
|
||||
confirm: '0'
|
||||
which: '{{ apt_listchanges__apticron_which }}'
|
||||
save_seen: '/var/lib/apt/listchanges.db'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
# Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016-2022 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'Manage apt-listchanges service'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.0.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- apt
|
||||
- changelog
|
||||
- news
|
||||
- debian
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
# Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Manage APT packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ q("flattened", (apt_listchanges__base_packages
|
||||
+ apt_listchanges__packages)) }}'
|
||||
state: '{{ apt_listchanges__deploy_state }}'
|
||||
purge: True
|
||||
register: apt_listchanges__register_packages
|
||||
until: apt_listchanges__register_packages is succeeded
|
||||
|
||||
- name: Configure apt-listchanges
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/listchanges.conf.j2'
|
||||
dest: '/etc/apt/listchanges.conf'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
when: apt_listchanges__deploy_state == 'present'
|
||||
|
||||
- name: Make sure that Ansible fact directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Save apt-listchanges facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apt_listchanges.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apt_listchanges.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
tags: [ 'meta::facts' ]
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
from sys import exit
|
||||
from os import path
|
||||
|
||||
try:
|
||||
from configparser import ConfigParser
|
||||
except ImportError:
|
||||
from ConfigParser import ConfigParser
|
||||
|
||||
conf_file = '/etc/apt/listchanges.conf'
|
||||
output = {"installed": True}
|
||||
|
||||
if path.isfile(conf_file):
|
||||
config = ConfigParser()
|
||||
config.read(conf_file)
|
||||
|
||||
for section in config.sections():
|
||||
output[section] = {}
|
||||
|
||||
for name, value in config.items(section):
|
||||
output[section][name] = [x.strip() for x in value.split() if x]
|
||||
if len(output[section][name]) == 1:
|
||||
output[section][name] = output[section][name][0]
|
||||
elif len(output[section][name]) == 0:
|
||||
output[section][name] = ''
|
||||
|
||||
else:
|
||||
output = {"installed": False}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{# Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2016 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for name, profile in apt_listchanges__profiles | dictsort %}
|
||||
[{{ name }}]
|
||||
{% for key, value in profile | dictsort %}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
19
ansible_collections/debops/debops/roles/apt_mark/COPYRIGHT
Normal file
19
ansible_collections/debops/debops/roles/apt_mark/COPYRIGHT
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
debops.apt_mark - Set desired APT package state using Ansible
|
||||
|
||||
Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_mark__ref_defaults:
|
||||
|
||||
# debops.apt_mark default variables
|
||||
# =================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# General configuration [[[
|
||||
# -------------------------
|
||||
|
||||
# .. envvar:: apt_mark__enabled [[[
|
||||
#
|
||||
# Enable or disable support for marking APT package state.
|
||||
apt_mark__enabled: True
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__autoremove_recommends_important [[[
|
||||
#
|
||||
# If ``True`` (default), APT will consider packages installed via
|
||||
# ``Recommends:`` dependencies as important and not remove them automatically.
|
||||
#
|
||||
# Any entries in the ``apt_mark__*_packages`` lists will enable autoremoval of
|
||||
# APT packages installed via ``Recommends:`` dependencies, which you can then
|
||||
# control by marking them as installed manually or automatically.
|
||||
apt_mark__autoremove_recommends_important: '{{ False
|
||||
if (apt_mark__default_packages | d()
|
||||
or apt_mark__packages | d()
|
||||
or apt_mark__group_packages | d()
|
||||
or apt_mark__host_packages | d())
|
||||
else True }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__autoremove_suggests_important [[[
|
||||
#
|
||||
# If ``True`` (default), APT will consider packages installed via ``Suggests:``
|
||||
# dependencies as important and not remove them automatically.
|
||||
#
|
||||
# Any entries in the ``apt_mark__*_packages`` lists will enable autoremoval of
|
||||
# APT packages installed via ``Suggests:`` dependencies, which you can then
|
||||
# control by marking them as installed manually or automatically.
|
||||
apt_mark__autoremove_suggests_important: '{{ False
|
||||
if (apt_mark__default_packages | d()
|
||||
or apt_mark__packages | d()
|
||||
or apt_mark__group_packages | d()
|
||||
or apt_mark__host_packages | d())
|
||||
else True }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT package state configuration [[[
|
||||
# -----------------------------------
|
||||
|
||||
# These lists define the APT packages which the role will operate on, and their
|
||||
# desired state. See :ref:`apt_mark__ref_packages` for more details.
|
||||
|
||||
# .. envvar:: apt_mark__default_packages [[[
|
||||
#
|
||||
# List of APT package states defined by the role
|
||||
apt_mark__default_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__packages [[[
|
||||
#
|
||||
# List of APT package states which should be applied on all hosts in the
|
||||
# Ansible inventory.
|
||||
apt_mark__packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__group_packages [[[
|
||||
#
|
||||
# List of APT package states which should be applied on hosts in a specific
|
||||
# Ansible inventory group.
|
||||
apt_mark__group_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__host_packages [[[
|
||||
#
|
||||
# List of APT package states which should be applied on specific hosts in the
|
||||
# Ansible inventory.
|
||||
apt_mark__host_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__dependent_packages [[[
|
||||
#
|
||||
# List of APT package states defined by other Ansible roles via role dependent
|
||||
# variables.
|
||||
apt_mark__dependent_packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mark__combined_packages [[[
|
||||
#
|
||||
# Variable which combines all of the APT state lists and is passed to the role
|
||||
# tasks.
|
||||
apt_mark__combined_packages: '{{ apt_mark__default_packages
|
||||
+ apt_mark__dependent_packages
|
||||
+ apt_mark__packages
|
||||
+ apt_mark__group_packages
|
||||
+ apt_mark__host_packages }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
from subprocess import Popen, PIPE
|
||||
import os
|
||||
import signal
|
||||
|
||||
|
||||
def run_command(command_args):
|
||||
"""Gather information about APT packages"""
|
||||
process = Popen(command_args, stdout=PIPE, stderr=PIPE,
|
||||
preexec_fn=os.setsid)
|
||||
stdout, stderr = process.communicate()
|
||||
if stdout:
|
||||
return stdout.decode('utf-8').strip().split('\n')
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
output = {'installed':
|
||||
run_command(["dpkg-query", "-f", "${binary:Package}\n", "-W"]),
|
||||
'auto': run_command(["apt-mark", "showauto"]),
|
||||
'hold': run_command(["apt-mark", "showhold"]),
|
||||
'manual': run_command(["apt-mark", "showmanual"])}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
from subprocess import Popen, PIPE
|
||||
import os
|
||||
import signal
|
||||
|
||||
|
||||
def run_command(command_args):
|
||||
"""Gather information about APT packages"""
|
||||
process = Popen(command_args, stdout=PIPE, stderr=PIPE,
|
||||
preexec_fn=os.setsid)
|
||||
stdout, stderr = process.communicate()
|
||||
if stdout:
|
||||
return stdout.decode('utf-8').strip().split('\n')
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
output = {'installed':
|
||||
run_command(["dpkg-query", "-f", "${binary:Package}\n", "-W"]),
|
||||
'auto': run_command(["apt-mark", "showauto"]),
|
||||
'hold': run_command(["apt-mark", "showhold"]),
|
||||
'manual': run_command(["apt-mark", "showmanual"])}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'Set desired APT package state using apt-mark'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '2.4.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- apt
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Import custom Ansible plugins
|
||||
ansible.builtin.import_role:
|
||||
name: 'ansible_plugins'
|
||||
|
||||
- name: Configure APT autoremove options
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/apt.conf.d/25autoremove-recommends.conf.j2'
|
||||
dest: '/etc/apt/apt.conf.d/25autoremove-recommends.conf'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
when: apt_mark__enabled | bool
|
||||
|
||||
- name: Check state of the APT packages
|
||||
ansible.builtin.script: 'script/apt-mark-status{{ "2" if (ansible_python_version is version_compare("3.5", "<")) else "3" }}'
|
||||
register: apt_mark__register_state
|
||||
changed_when: False
|
||||
check_mode: False
|
||||
when: apt_mark__enabled | bool
|
||||
|
||||
- name: Set facts about APT package state
|
||||
ansible.builtin.set_fact:
|
||||
apt_mark__fact_auto: '{{ (apt_mark__register_state.stdout | from_json)["auto"] }}'
|
||||
apt_mark__fact_hold: '{{ (apt_mark__register_state.stdout | from_json)["hold"] }}'
|
||||
apt_mark__fact_installed: '{{ (apt_mark__register_state.stdout | from_json)["installed"] }}'
|
||||
apt_mark__fact_manual: '{{ (apt_mark__register_state.stdout | from_json)["manual"] }}'
|
||||
when: apt_mark__enabled | bool
|
||||
|
||||
- name: Set package state as installed automatically
|
||||
ansible.builtin.command: apt-mark auto {{ ((item.packages | d([item.name])) | intersect(apt_mark__fact_installed)) | join(' ') }}
|
||||
with_items: '{{ apt_mark__combined_packages | debops.debops.parse_kv_items }}'
|
||||
register: apt_mark__register_auto
|
||||
changed_when: apt_mark__register_auto.changed | bool
|
||||
when: (apt_mark__enabled | bool and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| symmetric_difference(apt_mark__fact_manual) and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| difference(apt_mark__fact_auto) and
|
||||
item.state | d('manual') in ['auto', 'auto-hold', 'auto-unhold'])
|
||||
|
||||
- name: Set package state as installed manually
|
||||
ansible.builtin.command: apt-mark manual {{ ((item.packages | d([item.name]))
|
||||
| intersect(apt_mark__fact_installed)) | join(' ') }}
|
||||
with_items: '{{ apt_mark__combined_packages | debops.debops.parse_kv_items }}'
|
||||
register: apt_mark__register_manual
|
||||
changed_when: apt_mark__register_manual.changed | bool
|
||||
when: (apt_mark__enabled | bool and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| symmetric_difference(apt_mark__fact_auto) and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| difference(apt_mark__fact_manual) and
|
||||
item.state | d('manual') in ['manual', 'manual-hold', 'manual-unhold'])
|
||||
|
||||
- name: Hold current package state
|
||||
ansible.builtin.command: apt-mark hold {{ ((item.packages | d([item.name]))
|
||||
| intersect(apt_mark__fact_installed)) | join(' ') }}
|
||||
with_items: '{{ apt_mark__combined_packages | debops.debops.parse_kv_items }}'
|
||||
register: apt_mark__register_hold
|
||||
changed_when: apt_mark__register_hold.changed | bool
|
||||
when: (apt_mark__enabled | bool and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| difference(apt_mark__fact_hold) and
|
||||
item.state | d('manual') in ['hold', 'auto-hold', 'manual-hold'])
|
||||
|
||||
- name: Unhold current package state
|
||||
ansible.builtin.command: apt-mark unhold {{ ((item.packages | d([item.name]))
|
||||
| intersect(apt_mark__fact_installed)) | join(' ') }}
|
||||
with_items: '{{ apt_mark__combined_packages | debops.debops.parse_kv_items }}'
|
||||
register: apt_mark__register_unhold
|
||||
changed_when: apt_mark__register_unhold.changed | bool
|
||||
when: (apt_mark__enabled | bool and
|
||||
(item.packages | d([item.name]) | intersect(apt_mark__fact_installed))
|
||||
| intersect(apt_mark__fact_hold) and
|
||||
item.state | d('manual') in ['unhold', 'auto-unhold', 'manual-unhold'])
|
||||
|
||||
- name: Make sure that Ansible local facts directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
|
||||
- name: Save apt-mark local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apt_mark.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apt_mark.fact'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0755'
|
||||
tags: [ 'meta::facts' ]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import loads, dumps
|
||||
from sys import exit
|
||||
|
||||
output = loads("""{{ {'configured': True,
|
||||
'enabled': apt_mark__enabled | bool}
|
||||
| to_nice_json }}""")
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{# Copyright (C) 2018 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2018 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
// {{ ansible_managed }}
|
||||
|
||||
// Specify if APT should treat packages installed via Recommends or Suggests
|
||||
// dependencies as important. If True, they will not be considered for
|
||||
// autoremoval.
|
||||
APT::AutoRemove::RecommendsImportant "{{ apt_mark__autoremove_recommends_important | bool | lower }}";
|
||||
APT::AutoRemove::SuggestsImportant "{{ apt_mark__autoremove_suggests_important | bool | lower }}";
|
||||
19
ansible_collections/debops/debops/roles/apt_mirror/COPYRIGHT
Normal file
19
ansible_collections/debops/debops/roles/apt_mirror/COPYRIGHT
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
debops.apt_mirror - Create a mirror of multiple APT repositories
|
||||
|
||||
Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# .. _apt_mirror__ref_defaults:
|
||||
|
||||
# debops.apt_mirror default variables
|
||||
# ===================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# APT packages, UNIX environment, cron defaults [[[
|
||||
# -------------------------------------------------
|
||||
|
||||
# .. envvar:: apt_mirror__base_packages [[[
|
||||
#
|
||||
# List of Debian packages required for :command:`apt-mirror` support.
|
||||
apt_mirror__base_packages: [ 'apt-mirror' ]
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__packages [[[
|
||||
#
|
||||
# List of additional packages to install with :command:`apt-mirror` package.
|
||||
apt_mirror__packages: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__cron_environment [[[
|
||||
#
|
||||
# YAML dictionary which defines the environment variables (keys) and their
|
||||
# values which will be defined in the :command:`cron` runtime environment for
|
||||
# the :command:`apt-mirror` cron jobs. See :man:`crontab(5)` for details.
|
||||
apt_mirror__cron_environment: {}
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__cron_time [[[
|
||||
#
|
||||
# The default time specification for :command:`apt-mirror` cron jobs, specified
|
||||
# in the :man:`crontab(5)` format. This value can be overridden per-mirror
|
||||
# configuration using the ``item.cron_time`` parameter.
|
||||
apt_mirror__cron_time: "0 4\t* * *"
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__user [[[
|
||||
#
|
||||
# The UNIX account of the :command:`apt-mirror` service.
|
||||
apt_mirror__user: 'apt-mirror'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__group [[[
|
||||
#
|
||||
# The UNIX group of the :command:`apt-mirror` service.
|
||||
apt_mirror__group: 'apt-mirror'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Web server configuration [[[
|
||||
# ----------------------------
|
||||
|
||||
# .. envvar:: apt_mirror__fqdn [[[
|
||||
#
|
||||
# The Fully Qualified Domain Name on which mirrored APT repositories will be
|
||||
# published.
|
||||
apt_mirror__fqdn: '{{ ansible_fqdn }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__web_root [[[
|
||||
#
|
||||
# Absolute path to the directory with mirrored APT repositories.
|
||||
apt_mirror__web_root: '/var/spool/apt-mirror/mirror'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# The default :command:`apt-mirror` configuration options [[[
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# .. envvar:: apt_mirror__default_options [[[
|
||||
#
|
||||
# List of YAML dictionaries which define default set of :command:`apt-mirror`
|
||||
# configuration options. These options can be overridden in specific instances
|
||||
# if necessary. See :ref:`apt_mirror__ref_configuration` for more details.
|
||||
apt_mirror__default_options:
|
||||
|
||||
- name: 'base_path'
|
||||
value: '/var/spool/apt-mirror'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'mirror_path'
|
||||
value: '$base_path/mirror'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'skel_path'
|
||||
value: '$base_path/skel'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'var_path'
|
||||
value: '$base_path/var'
|
||||
state: 'dynamic'
|
||||
|
||||
- name: 'cleanscript'
|
||||
value: '$var_path/clean.sh'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'defaultarch'
|
||||
value: '<running host architecture>'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'postmirror_script'
|
||||
value: '$var_path/postmirror.sh'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'run_postmirror'
|
||||
value: 0
|
||||
state: 'comment'
|
||||
|
||||
- name: 'nthreads'
|
||||
value: 20
|
||||
|
||||
- name: '_tilde'
|
||||
value: 0
|
||||
# ]]]
|
||||
# ]]]
|
||||
# The :command:`apt-mirror` instance configuration [[[
|
||||
# ----------------------------------------------------
|
||||
|
||||
# The variables below define configuration of :command:`apt-mirror`
|
||||
# "instances". See :ref:`apt_mirror__ref_configuration` for more details.
|
||||
|
||||
# .. envvar:: apt_mirror__default_configuration [[[
|
||||
#
|
||||
# The default instance configuration defined by the role.
|
||||
apt_mirror__default_configuration:
|
||||
|
||||
- name: 'default'
|
||||
filename: 'mirror.list'
|
||||
sources:
|
||||
|
||||
- name: 'debian-stable'
|
||||
type: 'deb'
|
||||
uri: 'http://deb.debian.org/debian'
|
||||
suite: 'stable'
|
||||
components: [ 'main', 'contrib', 'non-free' ]
|
||||
state: 'comment'
|
||||
|
||||
- name: 'debian-stable-src'
|
||||
raw: 'deb-src http://deb.debian.org/debian stable main contrib non-free'
|
||||
state: 'comment'
|
||||
|
||||
- name: 'clean-debian'
|
||||
comment: 'Generate a clean.sh script for Debian mirror'
|
||||
type: 'clean'
|
||||
uri: 'http://deb.debian.org/debian'
|
||||
weight: 1000
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__configuration [[[
|
||||
#
|
||||
# The :command:`apt-mirror` instance configuration defined on all hosts in the
|
||||
# Ansible inventory.
|
||||
apt_mirror__configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__group_configuration [[[
|
||||
#
|
||||
# The :command:`apt-mirror` instance configuration defined on hosts in
|
||||
# a specific Ansible inventory group.
|
||||
apt_mirror__group_configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__host_configuration [[[
|
||||
#
|
||||
# The :command:`apt-mirror` instance configuration defined on specific hosts in the
|
||||
# Ansible inventory.
|
||||
apt_mirror__host_configuration: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_mirror__combined_configuration [[[
|
||||
#
|
||||
# Variable which combines all instance configuration variables and is used in
|
||||
# role tasks and templates.
|
||||
apt_mirror__combined_configuration: '{{ apt_mirror__default_configuration
|
||||
+ apt_mirror__configuration
|
||||
+ apt_mirror__group_configuration
|
||||
+ apt_mirror__host_configuration }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Configuration for other Ansible roles [[[
|
||||
# -----------------------------------------
|
||||
|
||||
# .. envvar:: apt_mirror__nginx__servers [[[
|
||||
#
|
||||
# List of :program:`nginx` server configurations managed by the
|
||||
# :ref:`debops.nginx` role.
|
||||
apt_mirror__nginx__dependent_servers:
|
||||
|
||||
- by_role: 'debops.apt_mirror'
|
||||
enabled: True
|
||||
ssl: False # disable port 443
|
||||
filename: 'debops.apt_mirror_http'
|
||||
name: '{{ apt_mirror__fqdn }}'
|
||||
root: '{{ apt_mirror__web_root }}'
|
||||
webroot_create: False
|
||||
location:
|
||||
'/': |
|
||||
try_files $uri $uri/ $uri.html /index.html =404;
|
||||
autoindex on;
|
||||
state: 'present'
|
||||
|
||||
- by_role: 'debops.apt_mirror'
|
||||
enabled: True
|
||||
listen: False # disable port 80
|
||||
filename: 'debops.apt_mirror_https'
|
||||
name: '{{ apt_mirror__fqdn }}'
|
||||
root: '{{ apt_mirror__web_root }}'
|
||||
webroot_create: False
|
||||
location:
|
||||
'/': |
|
||||
try_files $uri $uri/ $uri.html /index.html =404;
|
||||
autoindex on;
|
||||
state: '{{ "present" if (ansible_local.pki.enabled | d()) | bool else "absent" }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski'
|
||||
description: 'Manage mirrors of multiple APT repositories'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-or-later'
|
||||
min_ansible_version: '2.14.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- apt
|
||||
- mirror
|
||||
- proxy
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <http://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
- name: Import DebOps global handlers
|
||||
ansible.builtin.import_role:
|
||||
name: 'global_handlers'
|
||||
|
||||
- name: Install required packages
|
||||
ansible.builtin.package:
|
||||
name: '{{ (apt_mirror__base_packages + apt_mirror__packages) | flatten }}'
|
||||
state: 'present'
|
||||
register: apt_mirror__register_install
|
||||
until: apt_mirror__register_install is succeeded
|
||||
|
||||
- name: Get list of dpkg-stateoverride paths
|
||||
ansible.builtin.shell: |
|
||||
set -o nounset -o pipefail -o errexit && dpkg-statoverride --list | awk '{print $4}'
|
||||
args:
|
||||
executable: 'bash'
|
||||
register: apt_mirror__register_statoverride
|
||||
changed_when: False
|
||||
check_mode: False
|
||||
|
||||
# apt-mirror stores passwords included in URLs as plaintext inside of its
|
||||
# spool directory - it cannot be world-readable
|
||||
- name: Fix permissions for apt-mirror spool directory
|
||||
ansible.builtin.command: |
|
||||
dpkg-statoverride --update --add {{ apt_mirror__user }} {{ apt_mirror__group }} 0750 /var/spool/apt-mirror/var
|
||||
register: apt_mirror__register_statoverride_set
|
||||
changed_when: apt_mirror__register_statoverride_set.changed | bool
|
||||
when: '"/var/spool/apt-mirror/var" not in apt_mirror__register_statoverride.stdout_lines'
|
||||
|
||||
- name: Make sure that Ansible local facts directory exists
|
||||
ansible.builtin.file:
|
||||
path: '/etc/ansible/facts.d'
|
||||
state: 'directory'
|
||||
mode: '0755'
|
||||
|
||||
- name: Save apt_mirror local facts
|
||||
ansible.builtin.template:
|
||||
src: 'etc/ansible/facts.d/apt_mirror.fact.j2'
|
||||
dest: '/etc/ansible/facts.d/apt_mirror.fact'
|
||||
mode: '0755'
|
||||
notify: [ 'Refresh host facts' ]
|
||||
tags: [ 'meta::facts' ]
|
||||
|
||||
- name: Update Ansible facts if they were modified
|
||||
ansible.builtin.meta: 'flush_handlers'
|
||||
|
||||
- name: Divert the original apt-mirror configuration
|
||||
debops.debops.dpkg_divert:
|
||||
path: '{{ item }}'
|
||||
state: 'present'
|
||||
loop:
|
||||
- '/etc/apt/mirror.list'
|
||||
- '/etc/cron.d/apt-mirror'
|
||||
when: ansible_pkg_mgr == 'apt'
|
||||
|
||||
- name: Remove apt-mirror configuration if requested
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/etc/apt/" + (item.filename | d("mirror." + item.name + ".list")) }}'
|
||||
state: 'absent'
|
||||
loop: '{{ apt_mirror__combined_configuration | flatten
|
||||
| debops.debops.parse_kv_items(merge_keys=["sources"]) }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: item.state | d('present') == 'absent'
|
||||
|
||||
- name: Generate apt-mirror configuration files
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/mirror.list.j2'
|
||||
dest: '{{ "/etc/apt/" + (item.filename | d("mirror." + item.name + ".list")) }}'
|
||||
owner: '{{ apt_mirror__user }}'
|
||||
group: '{{ apt_mirror__group }}'
|
||||
mode: '0640'
|
||||
loop: '{{ apt_mirror__combined_configuration | flatten
|
||||
| debops.debops.parse_kv_items(defaults={"options": (apt_mirror__default_options | debops.debops.parse_kv_config)},
|
||||
merge_keys=["sources"]) }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: item.state | d('present') not in [ 'absent', 'ignore', 'init' ]
|
||||
|
||||
- name: Create data directories for separate mirror instances
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/var/spool/apt-mirror/var/var." + item.name }}'
|
||||
owner: '{{ apt_mirror__user }}'
|
||||
group: '{{ apt_mirror__group }}'
|
||||
mode: '0750'
|
||||
state: 'directory'
|
||||
loop: '{{ apt_mirror__combined_configuration | flatten
|
||||
| debops.debops.parse_kv_items(defaults={"options": (apt_mirror__default_options | debops.debops.parse_kv_config)},
|
||||
merge_keys=["sources"]) }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: item.state | d('present') not in [ 'absent', 'ignore', 'init' ]
|
||||
|
||||
- name: Create postmirror.sh script for separate mirror instances
|
||||
ansible.builtin.file:
|
||||
path: '{{ "/var/spool/apt-mirror/var/var." + item.name + "/postmirror.sh" }}'
|
||||
owner: '{{ apt_mirror__user }}'
|
||||
group: '{{ apt_mirror__group }}'
|
||||
mode: '0755'
|
||||
state: 'touch'
|
||||
modification_time: 'preserve'
|
||||
access_time: 'preserve'
|
||||
loop: '{{ apt_mirror__combined_configuration | flatten
|
||||
| debops.debops.parse_kv_items(defaults={"options": (apt_mirror__default_options | debops.debops.parse_kv_config)},
|
||||
merge_keys=["sources"]) }}'
|
||||
loop_control:
|
||||
label: '{{ {"name": item.name, "state": item.state | d("present")} }}'
|
||||
when: item.state | d('present') not in [ 'absent', 'ignore', 'init' ]
|
||||
|
||||
- name: Generate cron configuration for apt-mirror
|
||||
ansible.builtin.template:
|
||||
src: 'etc/cron.d/apt-mirror.j2'
|
||||
dest: '/etc/cron.d/apt-mirror'
|
||||
mode: '0644'
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!{{ ansible_python['executable'] }}
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
from __future__ import print_function
|
||||
from json import dumps
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
|
||||
def cmd_exists(cmd):
|
||||
return any(
|
||||
os.access(os.path.join(path, cmd), os.X_OK)
|
||||
for path in os.environ["PATH"].split(os.pathsep)
|
||||
)
|
||||
|
||||
|
||||
output = {'installed': cmd_exists('apt-mirror')}
|
||||
|
||||
print(dumps(output, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
############# config ##################
|
||||
#
|
||||
{% for element in item.options %}
|
||||
{% if element.name | d() and element.value is defined and element.state | d('present') not in [ 'absent', 'ignore' ] %}
|
||||
{% set element_comment = ('# ' if (element.state | d('present') in [ 'init', 'comment' ]) else '') %}
|
||||
{% if element.value is string and not element.value | bool %}
|
||||
{% set element_value = element.value %}
|
||||
{% elif element.value | bool and element.value is not iterable %}
|
||||
{% if element.value | string == '1' %}
|
||||
{% set element_value = element.value %}
|
||||
{% else %}
|
||||
{% set element_value = 'yes' %}
|
||||
{% endif %}
|
||||
{% elif not element.value | bool and element.value is not iterable %}
|
||||
{% if element.value is not none %}
|
||||
{% if element.value | int %}
|
||||
{% set element_value = element.value %}
|
||||
{% else %}
|
||||
{% if element.value | string == '0' %}
|
||||
{% set element_value = element.value %}
|
||||
{% else %}
|
||||
{% set element_value = 'no' %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if element.state | d('present') == 'dynamic' %}
|
||||
{% if element.name == 'var_path' %}
|
||||
{% set element_value = '$base_path/var/var.' + item.name %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if element.comment | d() %}
|
||||
{{ '' }}
|
||||
{{ element.comment | regex_replace('$\n', '') | comment(prefix='', postfix='') -}}
|
||||
{% endif %}
|
||||
{{ '{}set {} {}'.format(element_comment, element.name, element_value) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
#
|
||||
############# end config ##############
|
||||
|
||||
{% for element in item.sources %}
|
||||
{% if element.name | d() and element.state | d('present') not in [ 'absent', 'ignore' ] %}
|
||||
{% set element_comment = ('#' if (element.state | d('present') in [ 'init', 'comment' ]) else '') %}
|
||||
{% if element.raw | d() %}
|
||||
{% set element_value = element.raw %}
|
||||
{% elif element.type | d() and element.uri | d() %}
|
||||
{% set element_entry = [] %}
|
||||
{% set _ = element_entry.append(element.type) %}
|
||||
{% set _ = element_entry.append(element.uri) %}
|
||||
{% if element.suite | d() %}
|
||||
{% set _ = element_entry.append(element.suite) %}
|
||||
{% endif %}
|
||||
{% if element.component | d() %}
|
||||
{% set _ = element_entry.append(element.component) %}
|
||||
{% endif %}
|
||||
{% if element.components | d() %}
|
||||
{% set _ = element_entry.extend(element.components) %}
|
||||
{% endif %}
|
||||
{% set element_value = element_entry | join(' ') %}
|
||||
{% endif %}
|
||||
{% if element.comment | d() %}
|
||||
{{ '' }}
|
||||
{{ element.comment | regex_replace('$\n', '') | comment(prefix='', postfix='') -}}
|
||||
{% endif %}
|
||||
{{ '{}{}'.format(element_comment, element_value) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{# Copyright (C) 2023 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2023 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#}
|
||||
# {{ ansible_managed }}
|
||||
|
||||
#
|
||||
# Regular cron jobs for the apt-mirror package
|
||||
#
|
||||
|
||||
{% if apt_mirror__cron_environment %}
|
||||
{{ '# Environment variables' }}
|
||||
{% for key, value in apt_mirror__cron_environment.items() %}
|
||||
{{ '{}={}'.format(key, value) }}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% for element in apt_mirror__combined_configuration | debops.debops.parse_kv_items %}
|
||||
{% if element.name | d() and element.state | d('present') not in [ 'absent', 'ignore' ] %}
|
||||
{% set element_comment = ('#' if (element.state | d('present') in [ 'init', 'comment' ]) else '') %}
|
||||
{% set cron_time = element.cron_time | d(apt_mirror__cron_time) %}
|
||||
{% set cron_user = element.cron_user | d(apt_mirror__user) %}
|
||||
{% set cron_command = element.cron_command | d('/usr/bin/flock /var/spool/apt-mirror/var /usr/bin/apt-mirror /etc/apt/'
|
||||
+ (element.filename | d('mirror.' + element.name + '.list'))
|
||||
+ ' > /var/spool/apt-mirror/var/cron.' + element.name + '.log') %}
|
||||
{{ '{}{}\t{}\t{}'.format(element_comment, cron_time, cron_user, cron_command) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
debops.apt_preferences - Manage APT preferences using Ansible
|
||||
|
||||
Copyright (C) 2015-2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2015-2017 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This Ansible role is part of DebOps.
|
||||
|
||||
DebOps is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
DebOps is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DebOps. If not, see https://www.gnu.org/licenses/.
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2015-2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2015-2017 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_preferences__ref_defaults:
|
||||
|
||||
# apt_preferences default variables [[[
|
||||
# =====================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# APT preferences lists [[[
|
||||
# -------------------------
|
||||
|
||||
# .. envvar:: apt_preferences__list [[[
|
||||
#
|
||||
# List of :manpage:`apt_preferences(5)` pins to configure in
|
||||
# :file:`/etc/apt/preferences.d/`. These pins will be configured on all hosts
|
||||
# in the cluster, if set in :file:`inventory/group_vars/debops_all_hosts/`. See
|
||||
# :ref:`apt_preferences__list` for more details.
|
||||
apt_preferences__list: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_preferences__group_list [[[
|
||||
#
|
||||
# List of :manpage:`apt_preferences(5)` pins to configure in
|
||||
# :file:`/etc/apt/preferences.d/`. These pins will be configured on hosts in a
|
||||
# specified group, if set in :file:`inventory/group_vars/group_name/`. Only one
|
||||
# group "level" is supported.
|
||||
apt_preferences__group_list: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_preferences__host_list [[[
|
||||
#
|
||||
# List of :manpage:`apt_preferences(5)` pins to configure in
|
||||
# :file:`/etc/apt/preferences.d/`. These pins will be configured on specific
|
||||
# hosts, if set in :file:`inventory/host_vars/host_name/`.
|
||||
apt_preferences__host_list: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_preferences__dependent_list [[[
|
||||
#
|
||||
# List of :manpage:`apt_preferences(5)` pins to configure in
|
||||
# :file:`/etc/apt/preferences.d/`. This variable is meant to be used from a
|
||||
# role dependency in :file:`role/meta/main.yml` or in a playbook.
|
||||
apt_preferences__dependent_list: []
|
||||
# ]]]
|
||||
# ]]]
|
||||
# APT preference presets [[[
|
||||
# --------------------------
|
||||
|
||||
# This section contains presets of APT preferences intended for advanced users
|
||||
# who want to install software from different releases but want to keep there
|
||||
# main system on the stable release.
|
||||
#
|
||||
# When enabling these presets, you will need to set explicit preferences for
|
||||
# packages you want to install from different releases.
|
||||
# Examples for such explicit preferences can be found in the
|
||||
# `defaults file of the ypid.packages`_ (search for "Package origin presets for
|
||||
# Debian GNU/Linux").
|
||||
#
|
||||
# .. Debian backports have a priority of 100 by default so you will automatically
|
||||
# not upgrade to packages from them.
|
||||
#
|
||||
|
||||
# .. envvar:: apt_preferences__debian_stable_default_preset_list [[[
|
||||
#
|
||||
# Preset for the stable release of Debian GNU/Linux.
|
||||
#
|
||||
# Configuring this in APT is needed because releases (stable, testing,
|
||||
# unstable) have by default the same priority 500 so when including different
|
||||
# releases, APT would just select the newest version (usually unstable). To
|
||||
# avoid this, APT preferences are used to change the preferences to prefer
|
||||
# stable over testing over unstable.
|
||||
apt_preferences__debian_stable_default_preset_list:
|
||||
- package: '*'
|
||||
by_role: 'debops.apt_preferences'
|
||||
suffix: '_Debian'
|
||||
raw: |
|
||||
Explanation: Configure the installed release explicitly to slightly higher than the default priority of 500 so that release packages are preferred over third party repos.
|
||||
Package: *
|
||||
Pin: release o=Debian,n={{ ansible_distribution_release }}
|
||||
Pin-Priority: 550
|
||||
|
||||
Explanation: Configure the security updates explicitly to slightly higher than the default priority of 500 so that security updates are not missing
|
||||
Package: *
|
||||
Pin: release o=Debian,n={{ ansible_distribution_release }}-security
|
||||
Pin-Priority: 550
|
||||
|
||||
Explanation: Configure the stable-updates explicitly to slightly higher than the default priority of 500 so that stable-updates are not missing
|
||||
Package: *
|
||||
Pin: release o=Debian,n={{ ansible_distribution_release }}-updates
|
||||
Pin-Priority: 550
|
||||
|
||||
Explanation: Configure the installed release explicitly to slightly higher than the default priority of 500 so that release packages are preferred over third party repos.
|
||||
Package: *
|
||||
Pin: release o=Qubes Debian,n={{ ansible_distribution_release }}
|
||||
Pin-Priority: 550
|
||||
|
||||
Explanation: The default priority of packages from backports is 100 which is even lower then testing and unstable (500).
|
||||
Explanation: Prefer backports over testing and unstable but don’t automatically upgrade to them.
|
||||
Package: *
|
||||
Pin: release o=Debian Backports,n={{ ansible_distribution_release }}-backports
|
||||
Pin-Priority: 400
|
||||
|
||||
Explanation: Pin NeuroDebian with priority 80 which is lower then the official Debian backports (100).
|
||||
Explanation: This also works with this pinning configuration where Debian backports is
|
||||
Explanation: set to 400 and Debian testing is decreased to 50.
|
||||
Explanation: It is done here additionally to the neurodebian role to allow soft migration to extrepo.
|
||||
Package: *
|
||||
Pin: release o=NeuroDebian
|
||||
Pin-Priority: 80
|
||||
|
||||
Explanation: In case ansible_distribution_release is not (anymore) the current stable release don’t automatically upgrade to it.
|
||||
Package: *
|
||||
Pin: release o=Debian,a=stable
|
||||
Pin-Priority: 60
|
||||
|
||||
Explanation: Install packages from testing if no package with the same name is available in release archives or backports or other archives.
|
||||
Package: *
|
||||
Pin: release o=Debian,a=testing
|
||||
Pin-Priority: 50
|
||||
|
||||
Explanation: Only install packages from unstable if explicitly asked for or the package is pinned.
|
||||
Package: *
|
||||
Pin: release o=Debian,a=unstable
|
||||
Pin-Priority: -1
|
||||
|
||||
Explanation: Only install packages from experimental if explicitly asked for or the package is pinned.
|
||||
Package: *
|
||||
Pin: release o=Debian,a=experimental
|
||||
Pin-Priority: -1
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_preferences__preset_list [[[
|
||||
#
|
||||
# Appropriate preset for your distribution, when one is available.
|
||||
# To use it, add the following:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_preferences__list:
|
||||
# - '{{ apt_preferences__preset_list | list }}'
|
||||
#
|
||||
# to your inventory.
|
||||
#
|
||||
apt_preferences__preset_list: '{{
|
||||
((apt_preferences__debian_stable_default_preset_list | list) if (ansible_distribution == "Debian") else [])
|
||||
}}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Role pin defaults [[[
|
||||
# ---------------------
|
||||
|
||||
# .. envvar:: apt_preferences__priority_default [[[
|
||||
#
|
||||
# Default pin priority used, if custom priority is not specified in a pin
|
||||
# definition.
|
||||
apt_preferences__priority_default: 500
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_preferences__priority_version [[[
|
||||
#
|
||||
# Default pin priority used if custom priority is not specified in a versioned
|
||||
# pin definition.
|
||||
apt_preferences__priority_version: 1001
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Role internals [[[
|
||||
# ------------------
|
||||
|
||||
# .. envvar:: apt_preferences__next_release [[[
|
||||
#
|
||||
# Dictionary of future releases of current stable distributions. This is used to
|
||||
# check if the role can create autogenerated pins with preference for backported
|
||||
# packages from the ``<release>-backports`` repository.
|
||||
#
|
||||
# .. Redundant in the following places, please update all copies:
|
||||
#
|
||||
# * ansible/roles/debops.apt/defaults/main.yml
|
||||
# * ansible/roles/debops.apt_preferences/defaults/main.yml
|
||||
# * ansible/roles/debops.reprepro/defaults/main.yml
|
||||
# * ansible/playbooks/tools/dist-upgrade.yml
|
||||
#
|
||||
apt_preferences__next_release:
|
||||
|
||||
# Debian releases
|
||||
'stretch': 'buster'
|
||||
'buster': 'bullseye'
|
||||
'bullseye': 'bookworm'
|
||||
'bookworm': 'trixie'
|
||||
'trixie': 'forky'
|
||||
|
||||
# Ubuntu releases
|
||||
'trusty': 'utopic'
|
||||
'utopic': 'vivid'
|
||||
'vivid': 'wily'
|
||||
'wily': 'xenial'
|
||||
'xenial': 'yakkety'
|
||||
|
||||
# ]]]
|
||||
# .. Documentation, external links [[[
|
||||
|
||||
# .. _`defaults file of the ypid.packages`: https://github.com/ypid/ansible-packages/blob/master/defaults/main.yml
|
||||
# ]]]
|
||||
# ]]]
|
||||
# ]]]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
# Copyright (C) 2015-2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2015-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
allow_duplicates: True
|
||||
|
||||
# Ensure that custom Ansible plugins and modules included in the main DebOps
|
||||
# collection are available to roles in other collections.
|
||||
collections: [ 'debops.debops' ]
|
||||
|
||||
dependencies: []
|
||||
|
||||
galaxy_info:
|
||||
|
||||
author: 'Maciej Delmanowski, Robin Schneider'
|
||||
description: 'Manage APT pins in /etc/apt/preferences.d/'
|
||||
company: 'DebOps'
|
||||
license: 'GPL-3.0-only'
|
||||
min_ansible_version: '1.7.0'
|
||||
|
||||
platforms:
|
||||
|
||||
- name: 'Ubuntu'
|
||||
versions: [ 'all' ]
|
||||
|
||||
- name: 'Debian'
|
||||
versions: [ 'all' ]
|
||||
|
||||
galaxy_tags:
|
||||
- system
|
||||
- apt
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# Copyright (C) 2015-2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2015-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
- name: Remove legacy APT preferences
|
||||
ansible.builtin.file:
|
||||
dest: '/etc/apt/preferences.d/{{ item.filename | d((item.role | d(item.by_role | d("pin")))
|
||||
+ "_" + ((item.package.split(" ")[0]
|
||||
if item.package is string
|
||||
else item.package[0])
|
||||
if item.package | d()
|
||||
else (item.packages.split(" ")[0]
|
||||
if item.packages is string
|
||||
else item.packages[0]))
|
||||
+ (item.suffix | d("")) + ".pref") | replace("*", "all") }}'
|
||||
state: 'absent'
|
||||
loop: '{{ q("flattened", apt_preferences_list | d([])
|
||||
+ apt_preferences_group_list | d([])
|
||||
+ apt_preferences_host_list | d([])
|
||||
+ apt_preferences_dependent_list | d([])
|
||||
+ apt_preferences__list
|
||||
+ apt_preferences__group_list
|
||||
+ apt_preferences__host_list
|
||||
+ apt_preferences__dependent_list) }}'
|
||||
when: ("." in item.role | d(item.by_role | d("")))
|
||||
|
||||
- name: Remove APT preferences
|
||||
ansible.builtin.file:
|
||||
dest: '/etc/apt/preferences.d/{{ item.filename | d((item.role | d(item.by_role | d("pin"))) | replace(".", "_")
|
||||
+ "_" + ((item.package.split(" ")[0]
|
||||
if item.package is string
|
||||
else item.package[0])
|
||||
if item.package | d()
|
||||
else (item.packages.split(" ")[0]
|
||||
if item.packages is string
|
||||
else item.packages[0]))
|
||||
+ (item.suffix | d("")) + ".pref") | replace("*", "all") }}'
|
||||
state: 'absent'
|
||||
loop: '{{ q("flattened", apt_preferences_list | d([])
|
||||
+ apt_preferences_group_list | d([])
|
||||
+ apt_preferences_host_list | d([])
|
||||
+ apt_preferences_dependent_list | d([])
|
||||
+ apt_preferences__list
|
||||
+ apt_preferences__group_list
|
||||
+ apt_preferences__host_list
|
||||
+ apt_preferences__dependent_list) }}'
|
||||
when: ((((item.state | d() and item.state == 'absent') or item.delete | d() | bool) and
|
||||
(item.package | d() or item.packages | d()) and
|
||||
(item.version is undefined or (item.version is defined and not item.version))) or
|
||||
(item.raw is undefined and
|
||||
item.pin is undefined and
|
||||
(item.backports is undefined or
|
||||
(item.backports is iterable and item.backports and
|
||||
ansible_distribution_release not in item.backports)) and
|
||||
ansible_distribution_release not in apt_preferences__next_release.keys()))
|
||||
|
||||
- name: Create APT preferences
|
||||
ansible.builtin.template:
|
||||
src: 'etc/apt/preferences.d/pin.pref.j2'
|
||||
dest: '/etc/apt/preferences.d/{{ item.filename | d((item.role | d(item.by_role | d("pin"))) | replace(".", "_")
|
||||
+ "_" + ((item.package.split(" ")[0]
|
||||
if item.package is string
|
||||
else item.package[0])
|
||||
if item.package | d()
|
||||
else (item.packages.split(" ")[0]
|
||||
if item.packages is string
|
||||
else item.packages[0]))
|
||||
+ (item.suffix | d("")) + ".pref") | replace("*", "all") }}'
|
||||
owner: 'root'
|
||||
group: 'root'
|
||||
mode: '0644'
|
||||
loop: '{{ q("flattened", apt_preferences_list | d([])
|
||||
+ apt_preferences_group_list | d([])
|
||||
+ apt_preferences_host_list | d([])
|
||||
+ apt_preferences_dependent_list | d([])
|
||||
+ apt_preferences__list
|
||||
+ apt_preferences__group_list
|
||||
+ apt_preferences__host_list
|
||||
+ apt_preferences__dependent_list) }}'
|
||||
when: ((((item.state | d('present')) != 'absent' and (not (item.delete | d() | bool))) and
|
||||
(item.package | d() or item.packages | d())) and
|
||||
(item.raw | d() or
|
||||
item.version | d() or
|
||||
(item.pin is undefined and
|
||||
(item.backports is undefined or
|
||||
(item.backports is iterable and item.backports and
|
||||
ansible_distribution_release in item.backports)) and
|
||||
ansible_distribution_release in apt_preferences__next_release.keys()) or
|
||||
item.pin | d()))
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{# Copyright (C) 2015-2016 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# Copyright (C) 2015-2017 Robin Schneider <ypid@riseup.net>
|
||||
# Copyright (C) 2015-2017 DebOps <https://debops.org/>
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#}
|
||||
{% if item.raw is undefined %}
|
||||
{% if item.role | d( item.by_role | d() ) %}
|
||||
Explanation: Pin added by role: {{ item.role | d(item.by_role) }}
|
||||
{% endif %}
|
||||
Explanation: {{ (item.reason | d('Reason not specified')).split('\n') | join('\nExplanation: ') }}
|
||||
{% if item.package | d() %}
|
||||
{% if item.package is string %}
|
||||
Package: {{ item.package }}
|
||||
{% else %}
|
||||
Package: {{ item.package | join(" ") }}
|
||||
{% endif %}
|
||||
{% elif item.packages | d() %}
|
||||
{% if item.packages is string %}
|
||||
Package: {{ item.packages }}
|
||||
{% else %}
|
||||
Package: {{ item.packages | join(" ") }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if item.when | d(True) | bool %}
|
||||
{% if item.version | d() %}
|
||||
Pin: version {{ item.version + '*' }}
|
||||
Pin-Priority: {{ item.priority | d(apt_preferences__priority_version) }}
|
||||
{% else %}
|
||||
Pin: {{ item.pin | d('release a=' + ansible_distribution_release + '-backports') }}
|
||||
Pin-Priority: {{ item.priority | d(apt_preferences__priority_default) }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
Explanation: Pin disabled by item.when condition
|
||||
{% endif %}
|
||||
{% elif item.raw | d() %}
|
||||
{{ item.raw }}
|
||||
{% endif %}
|
||||
18
ansible_collections/debops/debops/roles/apt_proxy/COPYRIGHT
Normal file
18
ansible_collections/debops/debops/roles/apt_proxy/COPYRIGHT
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
debops.apt_proxy - Manage HTTP/HTTPS/FTP proxy for APT with Ansible
|
||||
|
||||
Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
---
|
||||
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
|
||||
|
||||
# .. Copyright (C) 2016-2017 Maciej Delmanowski <drybjed@gmail.com>
|
||||
# .. Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
|
||||
# .. Copyright (C) 2016-2017 DebOps <https://debops.org/>
|
||||
# .. SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
# .. _apt_proxy__ref_defaults:
|
||||
|
||||
# debops.apt_proxy default variables [[[
|
||||
# ======================================
|
||||
|
||||
# .. contents:: Sections
|
||||
# :local:
|
||||
#
|
||||
# .. include:: ../../../../includes/global.rst
|
||||
|
||||
|
||||
# Required packages [[[
|
||||
# ---------------------
|
||||
|
||||
# .. envvar:: apt_proxy__base_packages [[[
|
||||
#
|
||||
# List of base packages to install.
|
||||
apt_proxy__base_packages:
|
||||
- '{{ ["python3-apt"]
|
||||
if (apt_proxy__temporally_avoid_unreachable | bool)
|
||||
else [] }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Main configuration [[[
|
||||
# ----------------------
|
||||
|
||||
# .. envvar:: apt_proxy__deploy_state [[[
|
||||
#
|
||||
# Specify if an APT proxy configuration should be present or absent. It will be
|
||||
# automatically enabled if :envvar:`apt_proxy__http_url`, :envvar:`apt_proxy__https_url` or
|
||||
# :envvar:`apt_proxy__ftp_url` are set in the host environment. See
|
||||
# :ref:`debops.environment` role for more details.
|
||||
apt_proxy__deploy_state: '{{ "present"
|
||||
if (apt_proxy__http_url or
|
||||
apt_proxy__https_url or
|
||||
apt_proxy__ftp_url)
|
||||
else "absent" }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__filename [[[
|
||||
#
|
||||
# Name of the configuration file used by the role in :file:`/etc/apt/apt.conf.d/`.
|
||||
# You shouldn't change this name when ``debops.apt_proxy`` is enabled.
|
||||
apt_proxy__filename: '00apt_proxy'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# HTTP proxy configuration [[[
|
||||
# ----------------------------
|
||||
|
||||
# .. envvar:: apt_proxy__http_url [[[
|
||||
#
|
||||
# The URL of the HTTP proxy used by APT. If empty, HTTP proxy won't be enabled.
|
||||
apt_proxy__http_url: '{{ ansible_env.http_proxy | d() }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__http_direct [[[
|
||||
#
|
||||
# List of hostnames to which APT should connect directly instead of through
|
||||
# HTTP proxy.
|
||||
apt_proxy__http_direct: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__http_options [[[
|
||||
#
|
||||
# A YAML dictionary with key/value parameters for the HTTP proxy. Each key is
|
||||
# the name of the ``Acquire::HTTP::*`` APT configuration option, and value is
|
||||
# it's value. The keys containing ``::`` sequences need to be quoted.
|
||||
# See :manpage:`apt.conf(5)` for more information. Example:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_proxy__http_options:
|
||||
# User-Agent: 'Debian APT-HTTP/1.3'
|
||||
#
|
||||
apt_proxy__http_options: {}
|
||||
# ]]]
|
||||
# ]]]
|
||||
# HTTPS proxy configuration [[[
|
||||
# -----------------------------
|
||||
|
||||
# .. envvar:: apt_proxy__https_url [[[
|
||||
#
|
||||
# The URL of the HTTPS proxy used by APT. If empty, HTTPS proxy won't be
|
||||
# enabled.
|
||||
apt_proxy__https_url: '{{ ansible_env.https_proxy | d() }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__https_direct [[[
|
||||
#
|
||||
# List of hostnames to which APT should connect directly instead of through
|
||||
# HTTPS proxy.
|
||||
apt_proxy__https_direct: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__https_options [[[
|
||||
#
|
||||
# A YAML dictionary with key/value parameters for the HTTPS proxy. Each key is
|
||||
# the name of the ``Acquire::HTTPS::*`` APT configuration option, and value is
|
||||
# it's value. The keys containing ``::`` sequences need to be quoted.
|
||||
# See :manpage:`apt.conf(5)` for more information. Example:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_proxy__https_options:
|
||||
# User-Agent: 'Debian APT-HTTP/1.3'
|
||||
#
|
||||
apt_proxy__https_options: {}
|
||||
# ]]]
|
||||
# ]]]
|
||||
# FTP proxy configuration [[[
|
||||
# ---------------------------
|
||||
|
||||
# .. envvar:: apt_proxy__ftp_url [[[
|
||||
#
|
||||
# The URL of the FTP proxy used by APT. If empty, FTP proxy won't be
|
||||
# enabled.
|
||||
apt_proxy__ftp_url: '{{ ansible_env.ftp_proxy | d() }}'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__ftp_direct [[[
|
||||
#
|
||||
# List of hostnames to which APT should connect directly instead of through
|
||||
# FTP proxy.
|
||||
apt_proxy__ftp_direct: []
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__ftp_login [[[
|
||||
#
|
||||
# List of commands sent to the FTP proxy to login to it and specify what host
|
||||
# to connect to. See :manpage:`apt.conf(5)` for more details.
|
||||
apt_proxy__ftp_login:
|
||||
- 'USER $(PROXY_USER)'
|
||||
- 'PASS $(PROXY_PASS)'
|
||||
- 'USER $(SITE_USER)@$(SITE):$(SITE_PORT)'
|
||||
- 'PASS $(SITE_PASS)'
|
||||
|
||||
# ]]]
|
||||
# .. envvar:: apt_proxy__ftp_options [[[
|
||||
#
|
||||
# A YAML dictionary with key/value parameters for the FTP proxy. Each key is
|
||||
# the name of the ``Acquire::FTP::*`` APT configuration option, and value is
|
||||
# it's value. The keys containing ``::`` sequences need to be quoted.
|
||||
# See :manpage:`apt.conf(5)` for more information. Example:
|
||||
#
|
||||
# .. code-block:: yaml
|
||||
# :linenos:
|
||||
#
|
||||
# apt_proxy__ftp_options:
|
||||
# 'Proxy::Passive": 'true'
|
||||
#
|
||||
apt_proxy__ftp_options: {}
|
||||
# ]]]
|
||||
# ]]]
|
||||
# Proxy online detection [[[
|
||||
# --------------------------
|
||||
|
||||
# By default (Debian, DebOps), APT will fail when the configured proxy can not
|
||||
# be reached.
|
||||
#
|
||||
# DebOps provides a script which hooks into APT using a
|
||||
# ``Acquire::HTTP::Proxy-Auto-Detect`` script which checks if the proxy is
|
||||
# currently reachable.
|
||||
# With this, APT will fall back to "DIRECT" (no proxy) if the proxy
|
||||
# is (temporally) not reachable.
|
||||
|
||||
# .. envvar:: apt_proxy__temporally_avoid_unreachable [[[
|
||||
#
|
||||
# Configures the behaviour if the proxy is not reachable.
|
||||
# ``True`` will cause APT to silently ignore offline proxies.
|
||||
# ``False`` will cause APT to return with an error if the proxy is offline.
|
||||
# This is currently only supported for HTTPS and HTTP proxies.
|
||||
apt_proxy__temporally_avoid_unreachable: False
|
||||
# ]]]
|
||||
|
||||
# .. envvar:: apt_proxy__proxy_auto_detect [[[
|
||||
#
|
||||
# Value to set as ``Acquire::HTTP::Proxy-Auto-Detect``. Set to ``{{ omit }}`` to
|
||||
# avoid setting it.
|
||||
apt_proxy__proxy_auto_detect: '{{ "/usr/local/lib/get-reachable-apt-proxy"
|
||||
if (apt_proxy__temporally_avoid_unreachable | bool)
|
||||
else omit }}'
|
||||
# ]]]
|
||||
# ]]]
|
||||
# ]]]
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue