diff --git a/Makefile b/Makefile
index 3712511c..89286310 100644
--- a/Makefile
+++ b/Makefile
@@ -35,9 +35,9 @@ DOCS_SRC_DIR=./docs/src
SPEECHDIR=./docs/speeches
TYPEDIR=./cdist/conf/type
-SPHINXM=make -C $(DOCS_SRC_DIR) man
-SPHINXH=make -C $(DOCS_SRC_DIR) html
-SPHINXC=make -C $(DOCS_SRC_DIR) clean
+SPHINXM=$(MAKE) -C $(DOCS_SRC_DIR) man
+SPHINXH=$(MAKE) -C $(DOCS_SRC_DIR) html
+SPHINXC=$(MAKE) -C $(DOCS_SRC_DIR) clean
################################################################################
# Manpages
diff --git a/bin/cdist-build-helper b/bin/cdist-build-helper
index 0380b3f8..cadddae7 100755
--- a/bin/cdist-build-helper
+++ b/bin/cdist-build-helper
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
+# 2011-2022 Nico Schottelius (nico-cdist at schottelius.org)
# 2016-2019 Darko Poljak (darko.poljak at gmail.com)
#
# This file is part of cdist.
diff --git a/cdist/conf/explorer/lsb_codename b/cdist/conf/explorer/lsb_codename
index 26bb8e3d..c9fb5cdf 100755
--- a/cdist/conf/explorer/lsb_codename
+++ b/cdist/conf/explorer/lsb_codename
@@ -21,6 +21,9 @@
set +e
case "$("$__explorer/os")" in
+ checkpoint)
+ awk '{printf("%s\n", $(NF-1))}' /etc/cp-release
+ ;;
openwrt)
# shellcheck disable=SC1091
(. /etc/openwrt_release && echo "$DISTRIB_CODENAME")
diff --git a/cdist/conf/explorer/lsb_description b/cdist/conf/explorer/lsb_description
index b1009627..7279a9c2 100755
--- a/cdist/conf/explorer/lsb_description
+++ b/cdist/conf/explorer/lsb_description
@@ -21,6 +21,9 @@
set +e
case "$("$__explorer/os")" in
+ checkpoint)
+ cat /etc/cp-release
+ ;;
openwrt)
# shellcheck disable=SC1091
(. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION")
diff --git a/cdist/conf/explorer/lsb_id b/cdist/conf/explorer/lsb_id
index 82ff9977..1f91cc40 100755
--- a/cdist/conf/explorer/lsb_id
+++ b/cdist/conf/explorer/lsb_id
@@ -21,6 +21,9 @@
set +e
case "$("$__explorer/os")" in
+ checkpoint)
+ echo "CheckPoint"
+ ;;
openwrt)
# shellcheck disable=SC1091
(. /etc/openwrt_release && echo "$DISTRIB_ID")
diff --git a/cdist/conf/explorer/lsb_release b/cdist/conf/explorer/lsb_release
index 5ebfff1a..0bb9f7fe 100755
--- a/cdist/conf/explorer/lsb_release
+++ b/cdist/conf/explorer/lsb_release
@@ -21,6 +21,9 @@
set +e
case "$("$__explorer/os")" in
+ checkpoint)
+ sed /etc/cp-release -e 's/.* R\([1-9][0-9]*\)\.[0-9]*$/\1/'
+ ;;
openwrt)
# shellcheck disable=SC1091
(. /etc/openwrt_release && echo "$DISTRIB_RELEASE")
diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type
index 1c84f4d7..00646c75 100755
--- a/cdist/conf/explorer/machine_type
+++ b/cdist/conf/explorer/machine_type
@@ -1,8 +1,6 @@
-#!/bin/sh
+#!/bin/sh -e
#
-# 2014 Daniel Heule (hda at sfs.biz)
-# 2014 Thomas Oettli (otho at sfs.biz)
-# 2020 Evilham (contact at evilham.com)
+# 2021 Dennis Camera (cdist at dtnr.ch)
#
# This file is part of cdist.
#
@@ -19,91 +17,1019 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
#
+# This explorer tries to determine what type of machine the target to be
+# configured is (container, virtual machine, bare-metal).
+#
+# It will print one line for each layer it can detect.
+# The format of all lines is: TYPE[ VERB VENDOR]
+#
+# VERB does not have a special meaning, it is just for better readability.
+#
+# e.g.
+# container
+# container on lxc
+# virtual by kvm-spapr
+#
+# The third word of each line (except the first) can be composed of different
+# parts concatenated with a `-' (minus) character, with each component being
+# a specification of the previous, e.g.:
+# - lxc-libvirt (LXC container, managed by libvirt)
+# - lpar-s390 / lpar-power (LPAR running on IBM S/390 or POWER, respectively)
+# - xen-hvm / xen-pv (Xen HVM vs para-virtualization)
+#
+# If this explorer cannot collect enough information about virtualization it
+# will fall back to 'physical'.
+#
-os=$("$__explorer/os")
+# Add /sbin and /usr/sbin to the path so we can find system
+# binaries like dmidecode.
+PATH=$(getconf PATH 2>/dev/null) || PATH='/usr/bin:/bin'
+PATH="/sbin:/usr/sbin:${PATH}"
+export PATH
-vendor_string_to_machine_type() {
- for vendor in vmware bochs kvm qemu virtualbox bhyve; do
- if echo "${1}" | grep -q -i "${vendor}"; then
- if [ "${vendor}" = "bochs" ] || [ "${vendor}" = "qemu" ]; then
- vendor="kvm"
- fi
- echo "virtual_by_${vendor}"
- exit
- fi
- done
+arch=$(uname -m | sed -e 's/i.86/i386/' -e 's/arm.*/arm/')
+uname_s=$(uname -s)
+
+
+is_command() { command -v "$1" >/dev/null 2>&1; }
+
+files_same() {
+ # shellcheck disable=SC2012
+ LC_ALL=C df -P "$1" "$2" 2>/dev/null | {
+ read -r _ # skip header line
+ read -r fs1 _ _ _ _ mp1
+ read -r fs2 _ _ _ _ mp2
+ test "${fs1}" = "${fs2}" -a "${mp1}" = "${mp2}" || return 1
+ } &&
+ ls -1Ldi "$1" "$2" 2>/dev/null | {
+ read -r ino1 _
+ read -r ino2 _
+ test "${ino1}" = "${ino2}" || return 1
+ }
}
-case "$os" in
- "freebsd")
- # FreeBSD does not have /proc/cpuinfo even when procfs is used.
- # Instead there is a sysctl kern.vm_guest.
- # Which is 'none' if physical, else the virtualisation.
- vm_guest="$(sysctl -n kern.vm_guest 2>/dev/null || true)"
- if [ -n "${vm_guest}" ]; then
- if [ "${vm_guest}" = "none" ]; then
- echo "physical"
- exit
- fi
- echo "virtual_by_${vm_guest}"
- exit
- fi
- ;;
+is_oneof() (
+ x=$1; shift
+ for y
+ do
+ test "${x}" = "${y}" || continue
+ return 0
+ done
+ return 1
+)
- "openbsd")
- # OpenBSD can also use the sysctl's: hw.vendor or hw.product.
- # Note we can be reasonably sure about a machine being virtualised
- # as long as we can identify the virtualisation technology.
- # But not so much about it being physical...
- # Patches are welcome / reach out if you have better ideas.
- for sysctl in hw.vendor hw.product; do
- # This exits if we can make a reasonable judgement
- vendor_string_to_machine_type "$(sysctl -n "${sysctl}")"
- done
- ;;
+tolower() { LC_ALL=C tr '[:upper:]' '[:lower:]'; }
- *)
- # Defaulting to linux for compatibility with previous cdist behaviour
+# shellcheck disable=SC2086
+glob_exists() { set -- $1; test -e "$1"; }
- if [ -d "/proc/vz" ] && [ ! -d "/proc/bc" ]; then
- echo openvz
- exit
- fi
+get_dmi_field() {
+ if is_oneof "${uname_s}" NetBSD
+ then
+ case $1
+ in
+ (system-manufacturer) _mib=machdep.dmi.system-vendor ;;
+ (system-product-name) _mib=machdep.dmi.system-product ;;
+ (system-version|system-uuid) _mib=machdep.dmi.$1 ;;
+ (bios-vendor|bios-version) _mib=machdep.dmi.$1 ;;
+ (biod-release-date) _mib=machdep.dmi.bios-date ;;
+ (*) _mib= ;;
+ esac
- if [ -e "/proc/1/environ" ] &&
- tr '\000' '\n' < "/proc/1/environ" | grep -Eiq '^container='; then
- echo lxc
- exit
- fi
+ test -n "${_mib}" && get_sysctl "${_mib}" | grep -e . && return
+ fi
- if [ -r /proc/cpuinfo ]; then
- # this should only exist on virtual guest machines,
- # tested on vmware, xen, kvm, bhyve
- if grep -q "hypervisor" /proc/cpuinfo; then
- # this file is aviable in xen guest systems
- if [ -r /sys/hypervisor/type ]; then
- if grep -q -i "xen" /sys/hypervisor/type; then
- echo virtual_by_xen
- exit
- fi
- else
- for vendor_file in /sys/class/dmi/id/product_name \
- /sys/class/dmi/id/sys_vendor \
- /sys/class/dmi/id/chasis_vendor; do
- if [ -r ${vendor_file} ]; then
- # This exits if we can make a reasonable judgement
- vendor_string_to_machine_type "$(cat "${vendor_file}")"
- fi
- done
- fi
- echo "virtual_by_unknown"
- exit
- else
- echo "physical"
- exit
- fi
- fi
- ;;
-esac
+ if is_command dmidecode
+ then
+ dmidecode -s "$1"
+ elif test -d "${dmi_sysfs-}"
+ then
+ case $1
+ in
+ (system-manufacturer) _filename=sys_vendor ;;
+ (system-product-name) _filename=product_name ;;
+ (*) _filename=$(echo "$1" | tr - _) ;;
+ esac
+ if test -r "${dmi_sysfs-}/${_filename}"
+ then
+ cat "${dmi_sysfs}/${_filename}"
+ fi
+ unset _filename
+ elif test "${uname_s}" = OpenBSD
+ then
+ # NOTE: something similar to system-manufacutrer and system-product-name
+ # is available on OpenBSD in sysctl
+ case $1
+ in
+ (system-manufacturer) _mib=hw.vendor ;;
+ (system-product-name) _mib=hw.product ;;
+ (*) _mib= ;;
+ esac
-echo "unknown"
+ test -n "${_mib}" && get_sysctl "${_mib}" | grep -e . && return
+ fi
+
+ return 1
+}
+
+has_cpuinfo() { test -e /proc/cpuinfo; }
+
+get_sysctl() {
+ is_command sysctl && sysctl -n "$1" 2>/dev/null
+}
+
+detected_layer() {
+ test -n "${_toplayer:-}" || echo "${_toplayer:=${1:?}}"
+}
+
+
+# Check for chroot
+
+has_chroot_systemd() {
+ is_command systemd-detect-virt && systemd-detect-virt --help | grep -q -e '^ -r'
+}
+
+check_chroot_systemd() {
+ systemd-detect-virt -r
+}
+
+has_chroot_debian_ischroot() {
+ is_command ischroot
+}
+
+check_chroot_debian_ischroot() {
+ ischroot --default-false
+}
+
+has_chroot_procfs() {
+ test -d /proc/
+}
+
+check_chroot_procfs() (
+ is_chroot=false # default
+ if test -e /proc/1/root && ! files_same /proc/1/root /
+ then
+ is_chroot=true
+ fi
+ if test -e /proc/1/mountinfo -a -e /proc/self/mountinfo
+ then
+ has_mountinfo=true
+ cmp -s /proc/1/mountinfo /proc/self/mountinfo || is_chroot=true
+ fi
+
+ if ${is_chroot}
+ then
+ # try to determine where the chroot has been mounted
+ rootdev=$(LC_ALL=C df -P / | awk 'NR==2{print $1}')
+
+ if test -e "${rootdev}"
+ then
+ # escape chroot to determine where the device containing the
+ # chroot's / is mounted
+ rootdevmnt=$(LC_ALL=C chroot /proc/1/root df -P "${rootdev}" | awk 'NR==2{print $6}')
+
+ # shellcheck disable=SC2012
+ root_ino=$(ls -1di / | awk '{print $1}')
+
+ # escape chroot and find mount point by inode
+ chroot /proc/1/root find "${rootdevmnt}" -xdev -type d -inum "${root_ino}"
+ elif ${has_mountinfo}
+ then
+ while read -r mntid _ _ _ cmntpnt _
+ do
+ read -r _ _ _ _ hmntpnt _ <<-EOF
+ $(grep -e "^$((mntid)) " /proc/1/mountinfo)
+ EOF
+ printf '%s\n' "${hmntpnt%${cmntpnt}}"
+ done /dev/null) &&
+ case ${_ctengine}
+ in
+ (''|'none')
+ return 1 ;;
+ ('container-other')
+ return 0 ;;
+ ('systemd-nspawn')
+ echo systemd_nspawn ;;
+ (*)
+ echo "${_ctengine}" ;;
+ esac
+)
+
+has_ct_pid_1() {
+ test -r /run/systemd/container -o -r /proc/1/environ
+}
+
+translate_container_name() {
+ case $1
+ in
+ ('lxc')
+ echo lxc ;;
+ ('lxc-libvirt')
+ echo lxc-libvirt ;;
+ ('podman')
+ echo podman ;;
+ ('systemd-nspawn')
+ echo systemd_nspawn ;;
+ (*)
+ return 1 ;;
+ esac
+ return 0
+}
+
+check_ct_pid_1() {
+ if test -r /run/systemd/container
+ then
+ translate_container_name "$(head -n1 /run/systemd/container)" \
+ && return 0
+ fi
+
+ if test -r /proc/1/environ
+ then
+ translate_container_name "$(
+ LC_ALL=C tr '\000' '\n' /dev/null
+ then
+ # https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
+ echo wsl
+ elif test -d /var/.cagefs
+ then
+ # https://docs.cloudlinux.com/cloudlinux_os_components/#cagefs
+ # CageFS is not "really" a container, but it isn't a chroot either.
+ echo cagefs
+ elif test -e /proc/self/status && grep -q -e '^VxID: [0-9]\{1,\}' /proc/self/status
+ then
+ # Linux-VServer
+ if grep -q -x -F 'VxID: 0' /proc/self/status
+ then
+ # host
+ return 1
+ else
+ # guest
+ echo linux_vserver
+ fi
+ else
+ return 1
+ fi
+}
+
+check_ct_os_specific() (
+ if jailed=$(get_sysctl security.jail.jailed) && test "${jailed}" = 1
+ then
+ # FreeBSD jail
+ echo jail
+ return 0
+ fi
+
+ if is_command zonename && test "$(zonename)" != global
+ then
+ # Solaris zone
+ echo zone
+ return 0
+ fi
+
+ return 1
+)
+
+
+# Check for hypervisor
+
+guess_hypervisor_from_cpu_model() {
+ case $1
+ in
+ (*\ KVM\ *)
+ echo kvm ;;
+ (*\ QEMU\ *|QEMU\ *)
+ echo qemu ;;
+ (*)
+ return 1 ;;
+ esac
+}
+
+has_vm_systemd() {
+ is_command systemd-detect-virt && systemd-detect-virt --help | grep -q -e '^ -v'
+}
+
+check_vm_systemd() (
+ _hypervisor=$(systemd-detect-virt -v 2>/dev/null) &&
+ case ${_hypervisor}
+ in
+ (''|'none')
+ return 1 ;;
+ ('amazon')
+ echo aws ;;
+ ('bochs')
+ echo kvm ;;
+ ('microsoft')
+ # assumption
+ echo hyperv ;;
+ ('oracle')
+ echo virtualbox ;;
+ ('vm-other')
+ return 0 ;;
+ (*)
+ echo "${_hypervisor}" ;;
+ esac
+)
+
+has_vm_cpuinfo() { has_cpuinfo; }
+
+check_vm_cpuinfo() {
+ if grep -q -F 'User Mode Linux' /proc/cpuinfo \
+ || grep -q -F 'UML' /proc/cpuinfo
+ then
+ # User Mode Linux
+ echo uml
+ elif grep -q -e '^vendor_id.*: PowerVM Lx86' /proc/cpuinfo
+ then
+ # IBM PowerVM Lx86 (Linux/x86 emulator)
+ echo powervm_lx86
+ elif grep -q -e '^vendor_id.*: IBM/S390' /proc/cpuinfo
+ then
+ # IBM SystemZ (S/390)
+ if test -f /proc/sysinfo
+ then
+ if grep -q -e '^VM[0-9]* Control Program: KVM/Linux' /proc/sysinfo
+ then
+ echo kvm-s390
+ return 0
+ elif grep -q -e '^VM[0-9]* Control Program: z/VM' /proc/sysinfo
+ then
+ echo zvm
+ return 0
+ elif grep -q -e '^LPAR ' /proc/sysinfo
+ then
+ echo zvm-lpar
+ return 0
+ fi
+ fi
+ return 1
+ else
+ if grep -q -e '^model name.*:' /proc/cpuinfo
+ then
+ sed -n -e 's/^model name[^:]*: *//p' /proc/cpuinfo \
+ | while read -r _cpu_model
+ do
+ guess_hypervisor_from_cpu_model "${_cpu_model}"
+ done \
+ | sort \
+ | uniq -c \
+ | awk '
+ { if ($1 > most_c) { most_c = $1; most_s = $2 } }
+ END {
+ if (most_s) print most_s
+ exit !most_s
+ }' \
+ && return 0
+ fi
+ return 1
+ fi
+}
+
+check_vm_arch_specific() {
+ case ${arch}
+ in
+ (ppc64|ppc64le)
+ # Check PPC64 LPAR, KVM
+
+ # example /proc/cpuinfo line indicating 'not baremetal'
+ # platform : pSeries
+ #
+ # example /proc/ppc64/lparcfg systemtype line
+ # system_type=IBM pSeries (emulated by qemu)
+
+ if has_cpuinfo && grep -q -e 'platform.**pSeries' /proc/cpuinfo
+ then
+ if test -e /proc/ppc64/lparcfg
+ then
+ # Assume LPAR, now detect shared or dedicated
+ if grep -q -x -F 'shared_processor_mode=1' /proc/ppc64/lparcfg
+ then
+ echo powervm-shared
+ return 0
+ else
+ echo powervm-dedicated
+ return 0
+ fi
+ fi
+ fi
+ ;;
+ (sparc*)
+ # Check for SPARC LDoms
+
+ if test -e /dev/mdesc
+ then
+ if test -d /sys/class/vlds/ctrl -a -d /sys/class/vlds/sp
+ then
+ # control LDom
+ return 1
+ else
+ # guest LDom
+ echo ldom-sparc
+ fi
+
+ # MDPROP=/usr/lib/ldoms/mdprop.py
+ # if test -x "${MDPROP}"
+ # then
+ # if test -n "$("${MDPROP}" -v iodevice device-type=pciex)"
+ # then
+ # echo ldoms-root
+ # echo ldoms-io
+ # elif test -n "$("${MDPROP}" -v iov-device vf-id=0)"
+ # then
+ # echo ldoms-io
+ # fi
+ # fi
+ return 0
+ fi
+ ;;
+ (i?86|x86*|amd64|i86pc)
+ # VMM CPUID flag denotes that this system is running under a VMM
+ if is_oneof "${uname_s}" Darwin
+ then
+ get_sysctl machdep.cpu.features | tr ' ' '\n' | grep -qixF VMM \
+ && return 0
+ fi
+ if has_cpuinfo \
+ && grep -q -i -e '^flags.*:.*\(hypervisor\|vmm\)' /proc/cpuinfo
+ then
+ return 0
+ fi
+ ;;
+ (ia64)
+ if test -d /sys/bus/xen -a ! -d /sys/bus/xen-backend
+ then
+ # PV-on-HVM drivers installed in a Xen guest
+ echo xen-hvm
+ return 0
+ fi
+ ;;
+ esac
+ return 1
+}
+
+has_vm_dmi() {
+ # Check for various products in SMBIOS/DMI.
+ # Note that DMI doesn't exist on all architectures (only x86 and some ARM).
+ # On other architectures the $dmi variable will be empty.
+
+ if test -d /sys/class/dmi/id/
+ then
+ dmi_sysfs=/sys/class/dmi/id
+ elif test -d /sys/devices/virtual/dmi/id/
+ then
+ dmi_sysfs=/sys/devices/virtual/dmi/id
+ fi
+
+ # shellcheck disable=SC2015
+ {
+ is_command dmidecode \
+ && (
+ # dmidecode needs to exit 0 and not print the No SMBIOS/DMI line
+ dmi_out=$(dmidecode 2>&1) \
+ && ! printf '%s\n' "${dmi_out}" \
+ | grep -qF 'No SMBIOS nor DMI entry point found, sorry.'
+ ) \
+ || test -d "${dmi_sysfs}"
+ }
+}
+
+check_vm_dmi() {
+ case $(get_dmi_field system-product-name)
+ in
+ (*.metal)
+ if test "$(get_dmi_field system-manufacturer)" = 'Amazon EC2'
+ then
+ # AWS EC2 bare metal -> no virtualisation
+ return 1
+ fi
+ ;;
+ ('BHYVE')
+ echo bhyve
+ return 0
+ ;;
+ ('Google Compute Engine')
+ echo gce
+ return 0
+ ;;
+ ('RHEV Hypervisor')
+ # Red Hat Enterprise Virtualization
+ echo rhev
+ return 0
+ ;;
+ ('KVM'|'Bochs'|'KVM Virtual Machine')
+ echo kvm
+ return 0
+ ;;
+ ('Parallels Virtual Platform')
+ echo parallels
+ return 0
+ ;;
+ ('VirtualBox')
+ echo virtualbox
+ return 0
+ ;;
+ ('VMware Virtual Platform')
+ echo vmware
+ return 0
+ ;;
+ esac
+
+ case $(get_dmi_field system-manufacturer)
+ in
+ ('Alibaba'*)
+ case $(get_dmi_field system-product-name)
+ in
+ ('Alibaba Cloud ECS')
+ echo alibaba-ecs
+ ;;
+ (*)
+ echo alibaba
+ ;;
+ esac
+ return 0
+ ;;
+ ('Amazon EC2')
+ # AWS on bare-metal or KVM
+ echo aws-ec2
+ return 0
+ ;;
+ ('innotek GmbH'|'Oracle Corporation')
+ echo virtualbox
+ return 0
+ ;;
+ ('Joyent')
+ if test "$(get_dmi_field system-product-name)" = 'SmartDC HVM'
+ then
+ # SmartOS KVM
+ echo kvm-smartdc_hvm
+ return 0
+ fi
+ ;;
+ ('Microsoft Corporation'*)
+ if test "$(get_dmi_field system-product-name)" = 'Virtual Machine'
+ then
+ if test -e /proc/irq/7/hyperv \
+ || expr "$(get_dmi_field bios-version)" : 'VRTUAL.*' >/dev/null
+ then
+ echo hyperv
+ return 0
+ fi
+
+ case $(get_dmi_field system-version)
+ in
+ (VPC[0-9]*|VS2005*|*[Vv]irtual*[Pp][Cc]*)
+ echo virtualpc
+ return 0
+ ;;
+ (*)
+ echo hyperv
+ return 0
+ ;;
+ esac
+ fi
+ ;;
+ ('Nutanix')
+ # Nutanix AHV. Similar to KVM.
+ if test "$(get_dmi_field system-product-name)" = 'AHV'
+ then
+ echo nutanix_ahv
+ return 0
+ fi
+ ;;
+ ('oVirt')
+ echo ovirt
+ return 0
+ ;;
+ ('Parallels Software International Inc.')
+ echo parallels
+ return 0
+ ;;
+ ('QEMU')
+ echo qemu
+ return 0
+ ;;
+ ('VMware, Inc.')
+ echo vmware
+ return 0
+ ;;
+ esac
+
+ case $(get_dmi_field bios-vendor)
+ in
+ ('Amazon EC2')
+ # AWS on bare-metal or KVM
+ echo aws-ec2
+ return 0
+ ;;
+ ('BHYVE')
+ echo bhyve
+ return 0
+ ;;
+ ('innotek GmbH')
+ echo virtualbox
+ return 0
+ ;;
+ ('Parallels Software International Inc.')
+ echo parallels
+ return 0
+ ;;
+ ('Xen')
+ if get_dmi_field bios-version | grep -q -e '\([0-9]\{1,\}\.\)\{2\}amazon'
+ then
+ # AWS on Xen
+ echo aws-xen
+ return 0
+ fi
+ ;;
+ esac
+
+ return 1
+}
+
+check_vm_hyp_specific() {
+ if is_command vmware-checkvm && vmware-checkvm >/dev/null
+ then
+ # vmware-checkvm is provided by VMware's open-vm-tools
+ echo vmware
+ return 0
+ elif test -d /proc/xen
+ then
+ test -r /proc/xen/capabilities &&
+ if grep -q -F 'control_d' /proc/xen/capabilities 2>/dev/null
+ then
+ # Xen dom0
+ return 1
+ else
+ # Xen domU
+ echo xen
+ return 0
+ fi
+ fi
+ return 1
+}
+
+has_vm_dt() {
+ # OpenFirmware/Das U-Boot device-tree
+ test -d /proc/device-tree
+}
+
+check_vm_dt() {
+ case ${arch}
+ in
+ (arm|aarch64)
+ if test -r /proc/device-tree/hypervisor/compatible
+ then
+ if grep -q -F 'xen' /proc/device-tree/hypervisor/compatible
+ then
+ echo xen
+ return 0
+ elif grep -q -F 'vmware' /proc/device-tree/hypervisor/compatible
+ then
+ # e.g. VMware ESXi on ARM
+ echo vmware
+ return 0
+ fi
+ fi
+ if glob_exists /proc/device-tree/fw-cfg@*/compatible
+ then
+ # qemu,fw-cfg-mmio
+ sed -e 's/,.*$//' /proc/device-tree/fw-cfg@*/compatible | head -n1
+ return 0
+ fi
+ if grep -q -F 'dummy-virt' /proc/device-tree/compatible
+ then
+ echo lkvm
+ return 0
+ fi
+ ;;
+ (ppc64*)
+ if test -d /proc/device-tree/hypervisor \
+ && grep -qF 'linux,kvm' /proc/device-tree/hypervisor/compatible
+ then
+ # We are running as a spapr KVM guest on ppc64
+ echo kvm-spapr
+ return 0
+ fi
+ if test -r /proc/device-tree/ibm,partition-name \
+ && test -r /proc/device-tree/hmc-managed\? \
+ && test -r /proc/device-tree/chosen/qemu,graphic-width
+ then
+ echo powervm
+ fi
+ ;;
+ esac
+ return 1
+}
+
+has_vm_sys_hypervisor() {
+ test -d /sys/hypervisor/
+}
+
+check_vm_sys_hypervisor() {
+ test -r /sys/hypervisor/type &&
+ case $(head -n1 /sys/hypervisor/type)
+ in
+ (xen)
+ # Ordinary kernel with pv_ops. There does not seem to be
+ # enough information at present to tell whether this is dom0
+ # or domU.
+ echo xen
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+check_vm_os_specific() {
+ _hyp_generic=false
+
+ case ${uname_s}
+ in
+ (Darwin)
+ if hv_vmm_present=$(get_sysctl kern.hv_vmm_present) \
+ && test "${hv_vmm_present}" -ne 0
+ then
+ _hyp_generic=true
+ fi
+ ;;
+ (FreeBSD)
+ # FreeBSD does not have /proc/cpuinfo even when procfs is used.
+ # Instead there is a sysctl kern.vm_guest.
+ # Which is 'none' if physical, else the virtualisation.
+ vm_guest=$(get_sysctl kern.vm_guest | tolower) &&
+ case ${vm_guest}
+ in
+ (none) ;;
+ (generic) _hyp_generic=true ;;
+ (*)
+ # kernel could detect hypervisor
+ case ${vm_guest}
+ in
+ (hv) echo hyperv ;;
+ (vbox) echo virtualbox ;;
+ (*) echo "${vm_guest}" ;;
+ esac
+ return 0
+ ;;
+ esac
+ ;;
+ (NetBSD)
+ machdep_hv=$(get_sysctl machdep.hypervisor | tolower) &&
+ case ${machdep_hv}
+ in
+ (none) ;;
+ (generic) _hyp_generic=true ;;
+ (*)
+ # kernel could detect hypervisor
+ case ${machdep_hv}
+ in
+ (hyper-v) echo hyperv ;;
+ (xenhvm*) echo xen-hvm ;;
+ (xenpv*) echo xen-pv ;;
+ (xen*) echo xen ;;
+ (*) echo "${machdep_hv}" ;;
+ esac
+ return 0
+ ;;
+ esac
+ ;;
+ (OpenBSD)
+ if is_command hostctl && glob_exists /dev/pvbus[0-9]*
+ then
+ for _pvbus in /dev/pvbus[0-9]*
+ do
+ _h_out=$(hostctl -f "${_pvbus}" -t 2>/dev/null) || continue
+ case $(expr "${_h_out}" : '[^:]*: *\(.*\)$')
+ in
+ (KVM) echo kvm ;;
+ (Hyper-V) echo hyperv ;;
+ (VMware) echo vmware ;;
+ (Xen) echo xen ;;
+ (bhyve) echo bhyve ;;
+ (OpenBSD) echo openbsd_vmm ;;
+ esac
+ return 0
+ done
+ fi
+ ;;
+ (SunOS)
+ diag_conf=$(prtdiag | sed -n -e 's/.*Configuration: *//p' -e '/^$/q')
+ # NOTE: Don't use -e or -F in Solaris grep
+ if printf '%s\n' "${diag_conf}" | grep -q -i QEMU
+ then
+ echo qemu
+ return 0
+ elif printf '%s\n' "${diag_conf}" | grep -q -i VMware
+ then
+ echo vmware
+ return 0
+ fi
+ ;;
+ (Linux)
+ if is_command dmesg
+ then
+ while read -r line
+ do
+ case ${line}
+ in
+ ('Booting paravirtualized kernel on ')
+ case $(expr "${line}" : '.* kernel on \(.*\)')
+ in
+ ('Xen')
+ echo xen-pv; return 0 ;;
+ ('bare hardware')
+ return 1 ;;
+ esac
+ ;;
+ ('Hypervisor detected')
+ case $(expr "${line}" : '.*: *\(.*\)')
+ in
+ ('ACRN')
+ echo acrn ;;
+ ('Jailhouse')
+ echo jailhouse ;;
+ ('KVM')
+ echo kvm ;;
+ ('Microsoft Hyper-V')
+ echo hyperv ;;
+ ('VMware')
+ echo vmware ;;
+ ('Xen HVM')
+ echo xen-hvm ;;
+ ('Xen PV')
+ echo xen-pv ;;
+ esac
+ return 0
+ ;;
+ (lpar:*' under hypervisor')
+ return 0 ;;
+ esac
+ done <<-EOF
+ $(dmesg 2>/dev/null | awk '
+ /Booting paravirtualized kernel on /
+ /Hypervisor detected: /
+ /lpar: .* under hypervisor/
+ ')
+ EOF
+ fi
+ esac
+
+ # Try to guess hypervisor based on CPU model (sysctl hw.model if available)
+ if cpu_model=$(get_sysctl hw.model)
+ then
+ guess_hypervisor_from_cpu_model "${cpu_model}" && return 0
+ fi
+
+ if ${_hyp_generic}
+ then
+ # cannot say which hypervisor, but one was detected
+ return 0
+ else
+ return 1
+ fi
+}
+
+run_stage() {
+ if type "has_$1_$2" >/dev/null 2>&1
+ then
+ "has_$1_$2"
+ else
+ true
+ fi \
+ && "check_$1_$2"
+}
+
+
+# Execute chroot stages
+
+for stage in \
+ procfs debian_ischroot systemd
+do
+ chrootpnt=$(run_stage chroot ${stage}) || continue
+ is_chrooted=true
+ detected_layer 'chroot'
+ if test -n "${chrootpnt}"
+ then
+ echo chroot at "${chrootpnt}"
+ break
+ fi
+done
+if ${is_chrooted:-false} && test -z "${chrootpnt}"
+then
+ # could determine chroot, but not its mount point
+ echo chroot
+fi
+
+
+# Execute container stages
+
+for stage in \
+ systemd pid_1 cgroup files os_specific
+do
+ ctengine=$(run_stage ct ${stage}) || continue
+ detected_layer 'container'
+ is_contained=true
+ if test -n "${ctengine}"
+ then
+ echo container on "${ctengine}"
+ break
+ fi
+done
+if ${is_contained:-false} && test -z "${ctengine}"
+then
+ # none of the stages could determine the specific container engine, but
+ # we are running in some container.
+ echo container
+fi
+
+
+# Execute virtual machine / hypervisor stages
+
+for stage in \
+ systemd os_specific hyp_specific sys_hypervisor dt dmi cpuinfo arch_specific
+do
+ hypervisor=$(run_stage vm ${stage}) || continue
+ detected_layer 'virtual machine'
+ is_virtual=true
+ if test -n "${hypervisor}"
+ then
+ echo virtual by "${hypervisor}"
+ break
+ fi
+done
+if ${is_virtual:-false} && test -z "${hypervisor}"
+then
+ # none of the stages could determine the specific hypervisor, but
+ # we are virtual.
+ echo virtual
+fi
+
+
+# Fallback
+
+detected_layer physical
diff --git a/cdist/conf/explorer/memory b/cdist/conf/explorer/memory
index 63aba9c6..c6d113cf 100755
--- a/cdist/conf/explorer/memory
+++ b/cdist/conf/explorer/memory
@@ -27,19 +27,18 @@
str2bytes() {
awk -F' ' '
$2 == "B" || !$2 { print $1 }
- $2 == "kB" { print $1 * 1000 }
- $2 == "MB" { print $1 * 1000 * 1000 }
- $2 == "GB" { print $1 * 1000 * 1000 * 1000 }
- $2 == "TB" { print $1 * 1000 * 1000 * 1000 * 1000 }
- $2 == "kiB" { print $1 * 1024 }
- $2 == "MiB" { print $1 * 1024 * 1024 }
- $2 == "GiB" { print $1 * 1024 * 1024 * 1024 }
- $2 == "TiB" { print $1 * 1024 * 1024 * 1024 * 1024 }'
+ $2 == "kB" { printf "%.f\n", ($1 * 1000) }
+ $2 == "MB" { printf "%.f\n", ($1 * 1000 * 1000) }
+ $2 == "GB" { printf "%.f\n", ($1 * 1000 * 1000 * 1000) }
+ $2 == "TB" { printf "%.f\n", ($1 * 1000 * 1000 * 1000 * 1000) }
+ $2 == "kiB" { printf "%.f\n", ($1 * 1024) }
+ $2 == "MiB" { printf "%.f\n", ($1 * 1024 * 1024) }
+ $2 == "GiB" { printf "%.f\n", ($1 * 1024 * 1024 * 1024) }
+ $2 == "TiB" { printf "%.f\n", ($1 * 1024 * 1024 * 1024 * 1024) }'
}
bytes2kib() {
- set -- "$(cat)"
- test "$1" -gt 0 && echo $(($1 / 1024))
+ awk '$0 > 0 { printf "%.f\n", ($0 / 1024) }'
}
diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os
index 46d87f3e..b9232ee4 100755
--- a/cdist/conf/explorer/os
+++ b/cdist/conf/explorer/os
@@ -116,6 +116,13 @@ if [ -f /etc/slackware-version ]; then
exit 0
fi
+# Appliances
+
+if grep -q '^Check Point Gaia' /etc/cp-release 2>/dev/null; then
+ echo checkpoint
+ exit 0
+fi
+
uname_s="$(uname -s)"
# Assume there is no tr on the client -> do lower case ourselves
diff --git a/cdist/conf/explorer/os_release b/cdist/conf/explorer/os_release
index 6489446b..ec85046f 100644
--- a/cdist/conf/explorer/os_release
+++ b/cdist/conf/explorer/os_release
@@ -34,5 +34,9 @@ elif test -f /var/run/os-release
then
# FreeBSD (created by os-release service)
cat /var/run/os-release
+elif test -f /etc/cp-release
+then
+ # Checkpoint firewall or management (actually linux based)
+ cat /etc/cp-release
fi
diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version
index 3b02dedd..430200ae 100755
--- a/cdist/conf/explorer/os_version
+++ b/cdist/conf/explorer/os_version
@@ -1,6 +1,7 @@
-#!/bin/sh
+#!/bin/sh -e
#
# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org)
+# 2020-2021 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -17,12 +18,22 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
#
-#
# All os variables are lower case
#
-#
-case "$("$__explorer/os")" in
+rc_getvar() {
+ awk -F= -v varname="$2" '
+ function unquote(s) {
+ if (s ~ /^".*"$/ || s ~ /^'\''.*'\''$/)
+ return substr(s, 2, length(s) - 2)
+ else
+ return s
+ }
+ $1 == varname { print unquote(substr($0, index($0, "=") + 1)) }' "$1"
+}
+
+case $("${__explorer:?}/os")
+in
amazon)
cat /etc/system-release
;;
@@ -30,6 +41,9 @@ case "$("$__explorer/os")" in
# empty, but well...
cat /etc/arch-release
;;
+ checkpoint)
+ awk '{version=$NF; printf("%s\n", substr(version, 2))}' /etc/cp-release
+ ;;
debian)
debian_version=$(cat /etc/debian_version)
case $debian_version
@@ -43,6 +57,8 @@ case "$("$__explorer/os")" in
# sid versions don't have a number, so we decode by codename:
case $(expr "$debian_version" : '\([a-z]\{1,\}\)/')
in
+ trixie) echo 12.99 ;;
+ bookworm) echo 11.99 ;;
bullseye) echo 10.99 ;;
buster) echo 9.99 ;;
stretch) echo 8.99 ;;
@@ -50,7 +66,7 @@ case "$("$__explorer/os")" in
wheezy) echo 6.99 ;;
squeeze) echo 5.99 ;;
lenny) echo 4.99 ;;
- *) exit 1
+ *) echo 99.99 ;;
esac
;;
*)
@@ -59,7 +75,23 @@ case "$("$__explorer/os")" in
esac
;;
devuan)
- cat /etc/devuan_version
+ devuan_version=$(cat /etc/devuan_version)
+ case ${devuan_version}
+ in
+ (*/ceres)
+ # ceres versions don't have a number, so we decode by codename:
+ case ${devuan_version}
+ in
+ (chimaera/ceres) echo 3.99 ;;
+ (beowulf/ceres) echo 2.99 ;;
+ (ascii/ceres) echo 1.99 ;;
+ (*) exit 1
+ esac
+ ;;
+ (*)
+ echo "${devuan_version}"
+ ;;
+ esac
;;
fedora)
cat /etc/fedora-release
@@ -68,12 +100,20 @@ case "$("$__explorer/os")" in
cat /etc/gentoo-release
;;
macosx)
- sw_vers -productVersion
+ # NOTE: Legacy versions (< 10.3) do not support options
+ sw_vers | awk -F ':[ \t]+' '$1 == "ProductVersion" { print $2 }'
;;
freebsd)
# Apparently uname -r is not a reliable way to get the patch level.
# See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=251743
- freebsd-version
+ if command -v freebsd-version >/dev/null 2>&1
+ then
+ # get userland version
+ freebsd-version -u
+ else
+ # fallback to kernel release for FreeBSD < 10.0
+ uname -r
+ fi
;;
*bsd|solaris)
uname -r
@@ -98,7 +138,20 @@ case "$("$__explorer/os")" in
fi
;;
ubuntu)
- lsb_release -sr
+ if command -v lsb_release >/dev/null 2>&1
+ then
+ lsb_release -sr
+ elif test -r /usr/lib/os-release
+ then
+ # fallback to /usr/lib/os-release if lsb_release is not present (like
+ # on minimized Ubuntu installations)
+ rc_getvar /usr/lib/os-release VERSION_ID
+ elif test -r /etc/lsb-release
+ then
+ # extract DISTRIB_RELEASE= variable from /etc/lsb-release on old
+ # versions without /usr/lib/os-release.
+ rc_getvar /etc/lsb-release DISTRIB_RELEASE
+ fi
;;
alpine)
cat /etc/alpine-release
diff --git a/cdist/conf/type/__apt_backports/manifest b/cdist/conf/type/__apt_backports/manifest
index bc47d8de..6fcd9212 100755
--- a/cdist/conf/type/__apt_backports/manifest
+++ b/cdist/conf/type/__apt_backports/manifest
@@ -28,6 +28,7 @@
# lsb_release may not be given in all installations
codename_os_release() {
# shellcheck disable=SC1090
+ # shellcheck disable=SC1091
. "$__global/explorer/os_release"
printf "%s" "$VERSION_CODENAME"
}
diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state
index b7fe08fa..b464179a 100755
--- a/cdist/conf/type/__apt_mark/explorer/state
+++ b/cdist/conf/type/__apt_mark/explorer/state
@@ -24,4 +24,4 @@ else
name="$__object_id"
fi
-apt-mark showhold | grep -Fq "$name" && echo hold || echo unhold
+apt-mark showhold | grep -q "^${name}$" && echo hold || echo unhold
diff --git a/cdist/conf/type/__apt_pin/man.rst b/cdist/conf/type/__apt_pin/man.rst
new file mode 100644
index 00000000..4229c0cd
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/man.rst
@@ -0,0 +1,79 @@
+cdist-type__apt_pin(7)
+======================
+
+NAME
+----
+cdist-type__apt_pin - Manage apt pinning rules
+
+
+DESCRIPTION
+-----------
+Adds/removes/edits rules to pin some packages to a specific distribution. Useful if using multiple debian repositories at the same time. (Useful, if one wants to use a few specific packages from backports or perhaps Debain testing... or even sid.)
+
+
+REQUIRED PARAMETERS
+-------------------
+distribution
+ Specifies what distribution the package should be pinned to. Accepts both codenames (buster/bullseye/sid) and suite names (stable/testing/...).
+
+
+OPTIONAL PARAMETERS
+-------------------
+package
+ Package name, glob or regular expression to match (multiple) packages. If not specified `__object_id` is used.
+
+priority
+ The priority value to assign to matching packages. Deafults to 500. (To match the default target distro's priority)
+
+state
+ Will be passed to underlying `__file` type; see there for valid values and defaults.
+
+
+
+BOOLEAN PARAMETERS
+------------------
+None.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ # Add the bullseye repo to buster, but do not install any packages by default,
+ # only if explicitely asked for (-1 means "never" for apt)
+ __apt_pin bullseye-default \
+ --package "*" \
+ --distribution bullseye \
+ --priority -1
+
+ require="__apt_pin/bullseye-default" __apt_source bullseye \
+ --uri http://deb.debian.org/debian/ \
+ --distribution bullseye \
+ --component main
+
+ __apt_pin foo --package "foo foo-*" --distribution bullseye
+
+ __foo # Assuming, this installs the `foo` package internally
+
+ __package foo-plugin-extras # Assuming we also need some extra stuff
+
+
+SEE ALSO
+--------
+:strong:`apt_preferences`\ (5)
+:strong:`cdist-type__apt_source`\ (7)
+:strong:`cdist-type__apt_backports`\ (7)
+:strong:`cdist-type__file`\ (7)
+
+AUTHORS
+-------
+Daniel Fancsali
+
+
+COPYING
+-------
+Copyright \(C) 2021 Daniel Fancsali. 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.
diff --git a/cdist/conf/type/__apt_pin/manifest b/cdist/conf/type/__apt_pin/manifest
new file mode 100755
index 00000000..983b2b42
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/manifest
@@ -0,0 +1,68 @@
+#!/bin/sh -e
+#
+# 2021 Daniel Fancsali (fancsali@gmail.com)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+
+name="$__object_id"
+
+os=$(cat "$__global/explorer/os")
+state="$(cat "$__object/parameter/state")"
+
+if [ -f "$__object/parameter/package" ]; then
+ package="$(cat "$__object/parameter/package")"
+else
+ package=$name
+fi
+
+distribution="$(cat "$__object/parameter/distribution")"
+priority="$(cat "$__object/parameter/priority")"
+
+
+case "$os" in
+ debian|ubuntu|devuan)
+ ;;
+ *)
+ printf "This type is specific to Debian and it's derivatives" >&2
+ exit 1
+ ;;
+esac
+
+case $distribution in
+ stable|testing|unstable|experimental)
+ pin="release a=$distribution"
+ ;;
+ *)
+ pin="release n=$distribution"
+ ;;
+esac
+
+
+__file "/etc/apt/preferences.d/$name" \
+ --owner root --group root --mode 0644 \
+ --state "$state" \
+ --source - << EOF
+# Created by cdist ${__type##*/}
+# Do not change. Changes will be overwritten.
+#
+
+# $name
+Package: $package
+Pin: $pin
+Pin-Priority: $priority
+EOF
diff --git a/cdist/conf/type/__apt_pin/nonparallel b/cdist/conf/type/__apt_pin/nonparallel
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__apt_pin/parameter/default/priority b/cdist/conf/type/__apt_pin/parameter/default/priority
new file mode 100644
index 00000000..1b79f38e
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/parameter/default/priority
@@ -0,0 +1 @@
+500
diff --git a/cdist/conf/type/__apt_pin/parameter/default/state b/cdist/conf/type/__apt_pin/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__apt_pin/parameter/optional b/cdist/conf/type/__apt_pin/parameter/optional
new file mode 100644
index 00000000..847e703d
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/parameter/optional
@@ -0,0 +1,3 @@
+state
+package
+priority
diff --git a/cdist/conf/type/__apt_pin/parameter/required b/cdist/conf/type/__apt_pin/parameter/required
new file mode 100644
index 00000000..c8572d92
--- /dev/null
+++ b/cdist/conf/type/__apt_pin/parameter/required
@@ -0,0 +1 @@
+distribution
diff --git a/cdist/conf/type/__apt_ppa/files/remove-apt-repository b/cdist/conf/type/__apt_ppa/files/remove-apt-repository
deleted file mode 100755
index 3eb7d491..00000000
--- a/cdist/conf/type/__apt_ppa/files/remove-apt-repository
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python
-#
-# Remove the given apt repository.
-#
-# Exit with:
-# 0: if it worked
-# 1: if not
-# 2: on other error
-
-import os
-import sys
-from aptsources import distro, sourceslist
-from softwareproperties import ppa
-from softwareproperties.SoftwareProperties import SoftwareProperties
-
-
-def remove_if_empty(file_name):
- with open(file_name, 'r') as f:
- if f.read().strip():
- return
- os.unlink(file_name)
-
-def remove_repository(repository):
- #print 'repository:', repository
- codename = distro.get_distro().codename
- #print 'codename:', codename
- (line, file) = ppa.expand_ppa_line(repository.strip(), codename)
- #print 'line:', line
- #print 'file:', file
- deb_source_entry = sourceslist.SourceEntry(line, file)
- src_source_entry = sourceslist.SourceEntry('deb-src{}'.format(line[3:]), file)
-
- try:
- sp = SoftwareProperties()
- sp.remove_source(deb_source_entry)
- try:
- # If there's a deb-src entry, remove that too
- sp.remove_source(src_source_entry)
- except:
- pass
- remove_if_empty(file)
- return True
- except ValueError:
- print >> sys.stderr, "Error: '%s' doesn't exists in a sourcelist file" % line
- return False
-
-if __name__ == '__main__':
- if (len(sys.argv) != 2):
- print >> sys.stderr, 'Error: need a repository as argument'
- sys.exit(2)
- repository = sys.argv[1]
- if remove_repository(repository):
- sys.exit(0)
- else:
- sys.exit(1)
diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote
index 84ebebfe..e41341b8 100755
--- a/cdist/conf/type/__apt_ppa/gencode-remote
+++ b/cdist/conf/type/__apt_ppa/gencode-remote
@@ -29,9 +29,9 @@ fi
case "$state_should" in
present)
- echo "add-apt-repository '$name'"
+ echo "add-apt-repository -y '$name'"
;;
absent)
- echo "remove-apt-repository '$name'"
+ echo "add-apt-repository -r -y '$name'"
;;
esac
diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest
index c6f4e876..57e85442 100755
--- a/cdist/conf/type/__apt_ppa/manifest
+++ b/cdist/conf/type/__apt_ppa/manifest
@@ -20,9 +20,4 @@
__package software-properties-common
-require="__package/software-properties-common" \
- __file /usr/local/bin/remove-apt-repository \
- --source "$__type/files/remove-apt-repository" \
- --mode 0755
-
require="$__object_name" __apt_update_index
diff --git a/cdist/conf/type/__apt_source/files/source.list.template b/cdist/conf/type/__apt_source/files/source.list.template
index d4420e96..a28bb45f 100755
--- a/cdist/conf/type/__apt_source/files/source.list.template
+++ b/cdist/conf/type/__apt_source/files/source.list.template
@@ -2,13 +2,14 @@
set -u
entry="$uri $distribution $component"
+
cat << DONE
# Created by cdist ${__type##*/}
# Do not change. Changes will be overwritten.
#
# $name
-deb ${forcedarch} $entry
+deb ${options} $entry
DONE
if [ -f "$__object/parameter/include-src" ]; then
echo "deb-src $entry"
diff --git a/cdist/conf/type/__apt_source/gencode-remote b/cdist/conf/type/__apt_source/gencode-remote
index 1e8592c6..973b0f6c 100755
--- a/cdist/conf/type/__apt_source/gencode-remote
+++ b/cdist/conf/type/__apt_source/gencode-remote
@@ -22,7 +22,21 @@
name="$__object_id"
destination="/etc/apt/sources.list.d/${name}.list"
+# There are special arguments to apt(8) to prevent aborts if apt woudn't been
+# updated after the 19th April 2021 till the bullseye release. The additional
+# arguments acknoledge the happend suite change (the apt(8) update does the
+# same by itself).
+#
+# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
+# allows backward compatablility to pre-buster Debian versions.
+#
+# See more: ticket #861
+# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
+apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
+
+# run 'apt-get update' only if something changed with our sources.list file
+# it will be run a second time on error as a redundancy messure to success
if grep -q "^__file${destination}" "$__messages_in"; then
- printf 'apt-get update || apt-get update\n'
+ printf 'apt-get %s update || apt-get %s update\n' "$apt_opts" "$apt_opts"
fi
diff --git a/cdist/conf/type/__apt_source/man.rst b/cdist/conf/type/__apt_source/man.rst
index d1acb388..d317a135 100644
--- a/cdist/conf/type/__apt_source/man.rst
+++ b/cdist/conf/type/__apt_source/man.rst
@@ -23,6 +23,9 @@ OPTIONAL PARAMETERS
arch
set this if you need to force and specific arch (ubuntu specific)
+signed-by
+ provide a GPG key fingerprint or keyring path for signature checks
+
state
'present' or 'absent', defaults to 'present'
@@ -56,6 +59,11 @@ EXAMPLES
--uri http://archive.canonical.com/ \
--component partner --state present
+ __apt_source goaccess \
+ --uri http://deb.goaccess.io/ \
+ --component main \
+ --signed-by C03B48887D5E56B046715D3297BD1A0133449C3D
+
AUTHORS
-------
diff --git a/cdist/conf/type/__apt_source/manifest b/cdist/conf/type/__apt_source/manifest
index 35f15909..cdb526d3 100755
--- a/cdist/conf/type/__apt_source/manifest
+++ b/cdist/conf/type/__apt_source/manifest
@@ -31,9 +31,15 @@ fi
component="$(cat "$__object/parameter/component")"
if [ -f "$__object/parameter/arch" ]; then
- forcedarch="[arch=$(cat "$__object/parameter/arch")]"
-else
- forcedarch=""
+ options="arch=$(cat "$__object/parameter/arch")"
+fi
+
+if [ -f "$__object/parameter/signed-by" ]; then
+ options="$options signed-by=$(cat "$__object/parameter/signed-by")"
+fi
+
+if [ "$options" ]; then
+ options="[$options]"
fi
# export variables for use in template
@@ -41,7 +47,7 @@ export name
export uri
export distribution
export component
-export forcedarch
+export options
# generate file from template
mkdir "$__object/files"
diff --git a/cdist/conf/type/__apt_source/parameter/optional b/cdist/conf/type/__apt_source/parameter/optional
index 87537335..0b5470a1 100644
--- a/cdist/conf/type/__apt_source/parameter/optional
+++ b/cdist/conf/type/__apt_source/parameter/optional
@@ -1,4 +1,5 @@
state
distribution
component
-arch
\ No newline at end of file
+arch
+signed-by
diff --git a/cdist/conf/type/__apt_update_index/gencode-remote b/cdist/conf/type/__apt_update_index/gencode-remote
index 70b59710..2d7f9030 100755
--- a/cdist/conf/type/__apt_update_index/gencode-remote
+++ b/cdist/conf/type/__apt_update_index/gencode-remote
@@ -18,9 +18,23 @@
# along with cdist. If not, see .
#
+
+# There are special arguments to apt(8) to prevent aborts if apt woudn't been
+# updated after the 19th April 2021 till the bullseye release. The additional
+# arguments acknoledge the happend suite change (the apt(8) update does the
+# same by itself).
+#
+# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
+# allows backward compatablility to pre-buster Debian versions.
+#
+# See more: ticket #861
+# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
+apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
+
# run 'apt-get update' if anything in /etc/apt is newer then /var/lib/apt/lists
+# it will be run a second time on error as a redundancy messure to success
cat << DONE
if find /etc/apt -mindepth 1 -cnewer /var/lib/apt/lists | grep . > /dev/null; then
- apt-get update || apt-get update
+ apt-get $apt_opts update || apt-get $apt_opts update
fi
DONE
diff --git a/cdist/conf/type/__debconf_set_selections/parameter/deprecated/file b/cdist/conf/type/__debconf_set_selections/parameter/deprecated/file
new file mode 100644
index 00000000..09db545a
--- /dev/null
+++ b/cdist/conf/type/__debconf_set_selections/parameter/deprecated/file
@@ -0,0 +1 @@
+'file' has been deprecated in favour of 'line' in order to provide idempotency.
diff --git a/cdist/conf/type/__debconf_set_selections/parameter/deprecated b/cdist/conf/type/__debconf_set_selections/parameter/optional
similarity index 100%
rename from cdist/conf/type/__debconf_set_selections/parameter/deprecated
rename to cdist/conf/type/__debconf_set_selections/parameter/optional
diff --git a/cdist/conf/type/__dot_file/man.rst b/cdist/conf/type/__dot_file/man.rst
index ba7621a1..c8f36712 100644
--- a/cdist/conf/type/__dot_file/man.rst
+++ b/cdist/conf/type/__dot_file/man.rst
@@ -37,6 +37,12 @@ state
source
forwarded to :strong:`__file` type
+file
+ forwarded to :strong:`__file` type
+ This can be used if multiple users need to have a dotfile updated,
+ which will result in duplicate object id errors. When using the
+ file parameter the object id can be some unique value.
+
MESSAGES
--------
@@ -61,6 +67,15 @@ EXAMPLES
# Install default xmonad config for user 'eve'. Parent directory is created automatically.
__dot_file .xmonad/xmonad.hs --user eve --state exists --source "$__files/xmonad.hs"
+ # install .vimrc for root and some users
+ for user in root userx usery userz; do
+ __dot_file "${user}_dot_vimrc" \
+ --user $user \
+ --file .vimrc \
+ --state exists \
+ --source "$__files/$user/.vimrc"
+ done
+
SEE ALSO
--------
diff --git a/cdist/conf/type/__dot_file/manifest b/cdist/conf/type/__dot_file/manifest
index 02dadf05..a38ed943 100755
--- a/cdist/conf/type/__dot_file/manifest
+++ b/cdist/conf/type/__dot_file/manifest
@@ -20,13 +20,19 @@ user="$(cat "${__object}/parameter/user")"
home="$(cat "${__object}/explorer/home")"
primary_group="$(cat "${__object}/explorer/primary_group")"
dirmode="$(cat "${__object}/parameter/dirmode")"
+if [ -f "${__object}/parameter/file" ]; then
+ file="$(cat "${__object}/parameter/file")"
+else
+ file="${__object_id}"
+fi
+
# Create parent directory. Type __directory has flag 'parents', but it
# will leave us with root-owned directory in user home, which is not
# acceptable. So we create parent directories one-by-one. XXX: maybe
# it should be fixed in '__directory'?
set --
-subpath=${__object_id}
+subpath=${file}
while subpath="$(dirname "${subpath}")" ; do
[ "${subpath}" = . ] && break
set -- "${subpath}" "$@"
@@ -64,4 +70,4 @@ if [ "${source}" = "-" ] ; then
fi
unset source
-__file "${home}/${__object_id}" --owner "$user" --group "$primary_group" "$@"
+__file "${home}/${file}" --owner "$user" --group "$primary_group" "$@"
diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local
index 231b6927..5a303308 100755
--- a/cdist/conf/type/__file/gencode-local
+++ b/cdist/conf/type/__file/gencode-local
@@ -1,7 +1,7 @@
#!/bin/sh -e
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
-# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+# 2013-2022 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@@ -72,6 +72,7 @@ if [ "$state_should" = "present" ] || [ "$state_should" = "exists" ]; then
if [ "$type" != "file" ]; then
# destination is not a regular file, upload source to replace it
upload_file=1
+ echo upload >> "$__messages_out"
else
local_cksum="$(cksum < "$source")"
remote_cksum="$(cat "$__object/explorer/cksum")"
@@ -88,27 +89,39 @@ if [ "$state_should" = "present" ] || [ "$state_should" = "exists" ]; then
mkdir "$__object/files"
touch "$__object/files/set-attributes"
- # upload file to temp location
- tempfile_template="${destination}.cdist.XXXXXXXXXX"
- cat << DONE
-destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")"
-DONE
- if [ "$upload_file" ]; then
- echo upload >> "$__messages_out"
- # IPv6 fix
- if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$'
- then
- my_target_host="[${__target_host}]"
- else
- my_target_host="${__target_host}"
- fi
- cat << DONE
-$__remote_copy "$source" "${my_target_host}:\$destination_upload"
-DONE
+ if [ "$create_file" ]; then
+ # When creating an empty file we create it locally and then
+ # upload it so that permissions can be set before moving the file
+ # into place.
+ source="$__object/files/empty"
+ touch "$source"
fi
-# move uploaded file into place
-cat << DONE
-$__remote_exec $__target_host "rm -rf \"$destination\"; mv \"\$destination_upload\" \"$destination\""
+
+ # upload file to temp location
+ upload_destination="${destination}.cdist.${__cdist_object_marker}.$$"
+ # Yes, we are aware that this is a race condition.
+ # However:
+ # a) cdist usually writes to directories that are not user writable
+ # (probably > 99.9%)
+ # b) if they are user owned, the user / attacker always wins
+ # (probably < 0.1%)
+ # c) the only case which we could improve are tmp directories and we
+ # don't think managing tmp directories with cdist is a typical case
+ # ("the rest %)"
+
+ # Tell gencode-remote to where we uploaded the file so it can move
+ # it to its final destination.
+ echo "$upload_destination" > "$__object/files/upload-destination"
+
+ # IPv6 fix
+ if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$'
+ then
+ my_target_host="[${__target_host}]"
+ else
+ my_target_host="${__target_host}"
+ fi
+ cat << DONE
+$__remote_copy "$source" "${my_target_host}:${upload_destination}"
DONE
fi
fi
diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index f7a528fd..1a9ff69c 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -1,7 +1,7 @@
#!/bin/sh -e
#
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
-# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+# 2013-2022 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@@ -62,6 +62,13 @@ set_mode() {
case "$state_should" in
present|exists)
+ if [ -f "$__object/files/upload-destination" ]; then
+ final_destination="$destination"
+ # We change the 'global' $destination variable here so we can
+ # change attributes of the new/uploaded file before moving it
+ # to it's final destination.
+ destination="$(cat "$__object/files/upload-destination")"
+ fi
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
# clearing S_ISUID and S_ISGID bits (see chown(2))
for attribute in group owner mode; do
@@ -81,6 +88,11 @@ case "$state_should" in
fi
fi
done
+ if [ -f "$__object/files/upload-destination" ]; then
+ # move uploaded file into place
+ printf 'rm -rf "%s"\n' "$final_destination"
+ printf 'mv "%s" "%s"\n' "$destination" "$final_destination"
+ fi
if [ -f "$__object/files/set-attributes" ]; then
# set-attributes is created if file is created or uploaded in gencode-local
fire_onchange=1
diff --git a/cdist/conf/type/__filesystem/explorer/lsblk b/cdist/conf/type/__filesystem/explorer/lsblk
index 9be3c575..d376c09f 100644
--- a/cdist/conf/type/__filesystem/explorer/lsblk
+++ b/cdist/conf/type/__filesystem/explorer/lsblk
@@ -27,7 +27,7 @@ else
fi
case "$os" in
- alpine|centos|fedora|redhat|suse|gentoo)
+ alpine|centos|fedora|gentoo|redhat|suse|ubuntu)
if [ ! -x "$(command -v lsblk)" ]; then
echo "lsblk is required for __filesystem type" >&2
exit 1
diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest
index d145c4c3..0d944482 100755
--- a/cdist/conf/type/__grafana_dashboard/manifest
+++ b/cdist/conf/type/__grafana_dashboard/manifest
@@ -15,7 +15,7 @@ case $os in
# Differntation not needed anymore
apt_source_distribution=stable
;;
- 10*)
+ 10*|11*)
# Differntation not needed anymore
apt_source_distribution=stable
;;
diff --git a/cdist/conf/type/__haproxy_dualstack/files/http b/cdist/conf/type/__haproxy_dualstack/files/http
new file mode 100644
index 00000000..0508a465
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/files/http
@@ -0,0 +1,8 @@
+frontend http
+ bind BIND@:80
+ mode http
+ option httplog
+ default_backend http
+
+backend http
+ mode http
diff --git a/cdist/conf/type/__haproxy_dualstack/files/https b/cdist/conf/type/__haproxy_dualstack/files/https
new file mode 100644
index 00000000..73deac46
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/files/https
@@ -0,0 +1,10 @@
+frontend https
+ bind BIND@:443
+ mode tcp
+ option tcplog
+ tcp-request inspect-delay 5s
+ tcp-request content accept if { req_ssl_hello_type 1 }
+ default_backend https
+
+backend https
+ mode tcp
diff --git a/cdist/conf/type/__haproxy_dualstack/files/imaps b/cdist/conf/type/__haproxy_dualstack/files/imaps
new file mode 100644
index 00000000..b1ec3793
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/files/imaps
@@ -0,0 +1,12 @@
+frontend imaps
+ bind BIND@:143
+ bind BIND@:993
+
+ mode tcp
+ option tcplog
+ tcp-request inspect-delay 5s
+ tcp-request content accept if { req_ssl_hello_type 1 }
+ default_backend imaps
+
+backend imaps
+ mode tcp
diff --git a/cdist/conf/type/__haproxy_dualstack/files/smtps b/cdist/conf/type/__haproxy_dualstack/files/smtps
new file mode 100644
index 00000000..dce6ed4a
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/files/smtps
@@ -0,0 +1,12 @@
+frontend smtps
+ bind BIND@:25
+ bind BIND@:465
+
+ mode tcp
+ option tcplog
+ tcp-request inspect-delay 5s
+ tcp-request content accept if { req_ssl_hello_type 1 }
+ default_backend smtps
+
+backend smtps
+ mode tcp
diff --git a/cdist/conf/type/__haproxy_dualstack/man.rst b/cdist/conf/type/__haproxy_dualstack/man.rst
new file mode 100644
index 00000000..6c131cbe
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/man.rst
@@ -0,0 +1,121 @@
+cdist-type__haproxy_dualstack(7)
+================================
+
+
+NAME
+----
+cdist-type__haproxy_dualstack - Proxy services from a dual-stack server
+
+
+DESCRIPTION
+-----------
+This (singleton) type installs and configures haproxy to act as a dual-stack
+proxy for single-stack services.
+
+This can be useful to add IPv4 support to IPv6-only services while only using
+one IPv4 for many such services.
+
+By default this type uses the plain TCP proxy mode, which means that there is no
+need for TLS termination on this host when SNI is supported.
+This also means that proxied services will not receive the client's IP address,
+but will see the proxy's IP address instead (that of `$__target_host`).
+
+This can be solved by using the PROXY protocol, but do take into account that,
+e.g. nginx cannot serve both regular HTTP(S) and PROXY protocols on the same
+port, so you will need to use other ports for that.
+
+As a recommendation in this type: use TCP ports 8080 and 591 respectively to
+serve HTTP and HTTPS using the PROXY protocol.
+
+See the EXAMPLES for more details.
+
+
+OPTIONAL PARAMETERS
+-------------------
+v4proxy
+ Proxy incoming IPv4 connections to the equivalent IPv6 endpoint.
+ In its simplest use, it must be a NAME with an `AAAA` DNS entry, which is
+ the IP address actually providing the proxied services.
+ The full format of this argument is:
+ `[proxy:]NAME[[:PROTOCOL_1=PORT_1]...[:PROTOCOL_N=PORT_N]]`
+ Where starting with `proxy:` determines that the PROXY protocol must be
+ used and each `:PROTOCOL=PORT` (e.g. `:http=8080` or `:https=591`) is a PORT
+ override for the given PROTOCOL (see `--protocol`), if not present the
+ PROTOCOL's default port will be used.
+
+
+v6proxy
+ Proxy incoming IPv6 connections to the equivalent IPv4 endpoint.
+ In its simplest use, it must be a NAME with an `A` DNS entry, which is
+ the IP address actually providing the proxied services.
+ See `--v4proxy` for more options and details.
+
+protocol
+ Can be passed multiple times or as a space-separated list of protocols.
+ Currently supported protocols are: `http`, `https`, `imaps`, `smtps`.
+ This defaults to: `http https imaps smtps`.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ # Proxy the IPv6-only services so IPv4-only clients can access them
+ # This uses HAProxy's TCP mode for http, https, imaps and smtps
+ __haproxy_dualstack \
+ --v4proxy ipv6.chat \
+ --v4proxy matrix.ungleich.ch
+
+ # Proxy the IPv6-only HTTP(S) services so IPv4-only clients can access them
+ # Note this means that the backend IPv6-only server will only see
+ # the IPv6 address of the haproxy host managed by cdist, which can be
+ # troublesome if this information is relevant for analytics/security/...
+ # See the PROXY example below
+ __haproxy_dualstack \
+ --protocol http --protocol https \
+ --v4proxy ipv6.chat \
+ --v4proxy matrix.ungleich.ch
+
+ # Use the PROXY protocol to proxy the IPv6-only HTTP(S) services enabling
+ # IPv4-only clients to access them while maintaining the client's IP address
+ __haproxy_dualstack \
+ --protocol http --protocol https \
+ --v4proxy proxy:ipv6.chat:http=8080:https=591 \
+ --v4proxy proxy:matrix.ungleich.ch:http=8080:https=591
+ # Note however that the PROXY protocol is not compatible with regular
+ # HTTP(S) protocols, so your nginx will have to listen on different ports
+ # with the PROXY settings.
+ # Note that you will need to restrict access to the 8080 port to prevent
+ # Client IP spoofing.
+ # This can be something like:
+ # server {
+ # # listen for regular HTTP connections
+ # listen [::]:80 default_server;
+ # listen 80 default_server;
+ # # listen for PROXY HTTP connections
+ # listen [::]:8080 proxy_protocol;
+ # # Accept the Client's IP from the PROXY protocol
+ # real_ip_header proxy_protocol;
+ # }
+
+
+SEE ALSO
+--------
+- https://www.haproxy.com/blog/enhanced-ssl-load-balancing-with-server-name-indication-sni-tls-extension/
+- https://www.haproxy.com/blog/haproxy/proxy-protocol/
+- https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
+
+
+AUTHORS
+-------
+ungleich
+Evilham
+
+
+COPYING
+-------
+Copyright \(C) 2021 ungleich glarus ag. 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.
diff --git a/cdist/conf/type/__haproxy_dualstack/manifest b/cdist/conf/type/__haproxy_dualstack/manifest
new file mode 100644
index 00000000..d110eea6
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/manifest
@@ -0,0 +1,155 @@
+#!/bin/sh -eu
+
+__package haproxy
+require="__package/haproxy" __start_on_boot haproxy
+
+tmpdir="$__object/files"
+mkdir "$tmpdir"
+configtmp="$__object/files/haproxy.cfg"
+
+os=$(cat "$__global/explorer/os")
+case $os in
+ freebsd)
+ CONFIG_FILE="/usr/local/etc/haproxy.conf"
+ cat < "$configtmp"
+global
+ maxconn 4000
+ user nobody
+ group nogroup
+ daemon
+
+EOF
+
+ ;;
+ *)
+ CONFIG_FILE="/etc/haproxy/haproxy.cfg"
+ cat < "$configtmp"
+global
+ log [::1] local2
+ chroot /var/lib/haproxy
+ pidfile /var/run/haproxy.pid
+ maxconn 4000
+ user haproxy
+ group haproxy
+ daemon
+
+ # turn on stats unix socket
+ stats socket /var/lib/haproxy/stats
+
+EOF
+ ;;
+esac
+
+cat <> "$configtmp"
+defaults
+ retries 3
+ log global
+ timeout http-request 10s
+ timeout queue 1m
+ timeout connect 10s
+ timeout client 1m
+ timeout server 1m
+ timeout http-keep-alive 10s
+ timeout check 10s
+EOF
+
+dig_cmd="$(command -v dig || true)"
+get_ip() {
+ # Usage: get_ip (ipv4|ipv6) NAME
+ # uses "dig" if available, else fallback to "host"
+ case $1 in
+ ipv4)
+ if [ -n "${dig_cmd}" ]; then
+ ${dig_cmd} +short A "$2"
+ else
+ host -t A "$2" | cut -d ' ' -f 4 | grep -v 'found:'
+ fi
+ ;;
+ ipv6)
+ if [ -n "${dig_cmd}" ]; then
+ ${dig_cmd} +short AAAA "$2"
+ else
+ host -t AAAA "$2" | cut -d ' ' -f 5 | grep -v 'NXDOMAIN'
+ fi
+ ;;
+ esac
+}
+
+PROTOCOLS="$(cat "$__object/parameter/protocol")"
+
+for proxy in v4proxy v6proxy; do
+ param=$__object/parameter/$proxy
+ # no backend? skip generating code
+ if [ ! -f "$param" ]; then
+ continue
+ fi
+
+ # turn backend name into bind parameter: v4backend -> ipv4@
+ bind=$(echo $proxy | sed -e 's/^/ip/' -e 's/proxy//')
+
+ case $bind in
+ ipv4)
+ backendproto=ipv6
+ ;;
+ ipv6)
+ backendproto=ipv4
+ ;;
+ esac
+
+ for proto in ${PROTOCOLS}; do
+ # Add protocol "header"
+ printf "\n# %s %s \n" "${bind}" "${proto}" >> "$configtmp"
+
+ sed -e "s/BIND/$bind/" \
+ -e "s/\(frontend[[:space:]].*\)/\1$bind/" \
+ -e "s/\(backend[[:space:]].*\)/\\1$bind/" \
+ "$__type/files/$proto" >> "$configtmp"
+
+ while read -r hostdefinition; do
+ if echo "$hostdefinition" | grep -qE '^proxy:'; then
+ # Proxy protocol was requested
+ host="$(echo "$hostdefinition" | sed -E 's/^proxy:([^:]+).*$/\1/')"
+ send_proxy=" send-proxy"
+ else
+ # Just use tcp proxy mode
+ host="$hostdefinition"
+ send_proxy=""
+ fi
+ if echo "$hostdefinition" | grep -qE ":${proto}="; then
+ # Use custom port definition if requested
+ port="$(echo "$hostdefinition" | sed -E "s/^(.*:)?${proto}=([0-9]+).*$/:\2/")"
+ else
+ # Else use the default
+ port=""
+ fi
+ servername=$host
+
+ res=$(get_ip "$bind" "$servername")
+
+ if [ -z "$res" ]; then
+ echo "$servername does not resolve - aborting config" >&2
+ exit 1
+ fi
+
+ # Treat protocols without TLS+SNI specially
+ if [ "$proto" = http ]; then
+ echo " use-server $servername if { hdr(host) -i $host }" >> "$configtmp"
+ else
+ echo " use-server $servername if { req_ssl_sni -i $host }" >> "$configtmp"
+ fi
+
+ # Create the "server" itself.
+ # Note that port and send_proxy will be empty unless
+ # they were requested by the type user
+ echo " server $servername ${backendproto}@${host}${port}${send_proxy}" >> "$configtmp"
+
+ done < "$param"
+ done
+done
+
+# Create config file
+require="__package/haproxy" __file ${CONFIG_FILE} --source "$configtmp" --mode 0644
+
+require="__file${CONFIG_FILE}" __check_messages "haproxy_reload" \
+ --pattern "^__file${CONFIG_FILE}" \
+ --execute "service haproxy reload || service haproxy restart"
diff --git a/cdist/conf/type/__haproxy_dualstack/parameter/default/protocol b/cdist/conf/type/__haproxy_dualstack/parameter/default/protocol
new file mode 100644
index 00000000..dc8bb7bf
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/parameter/default/protocol
@@ -0,0 +1 @@
+http https imaps smtps
diff --git a/cdist/conf/type/__haproxy_dualstack/parameter/optional_multiple b/cdist/conf/type/__haproxy_dualstack/parameter/optional_multiple
new file mode 100644
index 00000000..8c482bd4
--- /dev/null
+++ b/cdist/conf/type/__haproxy_dualstack/parameter/optional_multiple
@@ -0,0 +1,3 @@
+protocol
+v4proxy
+v6proxy
diff --git a/cdist/conf/type/__haproxy_dualstack/singleton b/cdist/conf/type/__haproxy_dualstack/singleton
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest
index 6394f629..638a99e0 100644
--- a/cdist/conf/type/__letsencrypt_cert/manifest
+++ b/cdist/conf/type/__letsencrypt_cert/manifest
@@ -41,7 +41,7 @@ if [ -z "${certbot_fullpath}" ]; then
require="__apt_source/stretch-backports" __package_apt certbot \
--target-release stretch-backports
;;
- 10*)
+ 10*|11*)
__package_apt certbot
;;
diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote
index fbfca330..79c0d9d3 100755
--- a/cdist/conf/type/__package_apt/gencode-remote
+++ b/cdist/conf/type/__package_apt/gencode-remote
@@ -81,12 +81,24 @@ aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes -o Dpkg::Options::=
case "$state_should" in
present)
+ # There are special arguments to apt(8) to prevent aborts if apt woudn't been
+ # updated after the 19th April 2021 till the bullseye release. The additional
+ # arguments acknoledge the happend suite change (the apt(8) update does the
+ # same by itself).
+ #
+ # Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
+ # allows backward compatablility to pre-buster Debian versions.
+ #
+ # See more: ticket #861
+ # https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
+ apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
+
# following is bit ugly, but important hack.
# due to how cdist config run works, there isn't
# currently better way to do it :(
cat << EOF
if [ ! -f /var/cache/apt/pkgcache.bin ] || [ "\$( stat --format %Y /var/cache/apt/pkgcache.bin )" -lt "\$( date +%s -d '-1 day' )" ]
-then echo apt-get update > /dev/null 2>&1 || true
+then echo apt-get $apt_opts update > /dev/null 2>&1 || true
fi
EOF
if [ -n "$version" ]; then
diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote
index 3f88f6bc..ca9aa45a 100755
--- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote
+++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote
@@ -37,6 +37,7 @@ assert () # If condition false,
then
echo "Assertion failed: \"$1\""
# shellcheck disable=SC2039
+ # shellcheck disable=SC3044
echo "File \"$0\", line $lineno, called by $(caller 0)"
exit $E_ASSERT_FAILED
fi
diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote
index 803468b5..a10c16d3 100755
--- a/cdist/conf/type/__package_update_index/gencode-remote
+++ b/cdist/conf/type/__package_update_index/gencode-remote
@@ -41,7 +41,19 @@ fi
case "$type" in
yum) ;;
apt)
- echo "apt-get --quiet update"
+ # There are special arguments to apt(8) to prevent aborts if apt woudn't been
+ # updated after the 19th April 2021 till the bullseye release. The additional
+ # arguments acknoledge the happend suite change (the apt(8) update does the
+ # same by itself).
+ #
+ # Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
+ # allows backward compatablility to pre-buster Debian versions.
+ #
+ # See more: ticket #861
+ # https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
+ apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
+
+ echo "apt-get --quiet $apt_opts update"
echo "apt-cache updated (age was: $currage)" >> "$__messages_out"
;;
pacman)
diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote
index 38aa001e..d332e851 100755
--- a/cdist/conf/type/__package_upgrade_all/gencode-remote
+++ b/cdist/conf/type/__package_upgrade_all/gencode-remote
@@ -28,6 +28,10 @@ apt_clean="$__object/parameter/apt-clean"
apt_dist_upgrade="$__object/parameter/apt-dist-upgrade"
+if [ -f "$__object/parameter/apt-with-new-pkgs" ]; then
+ apt_with_new_pkgs="--with-new-pkgs"
+fi
+
if [ -f "$type" ]; then
type="$(cat "$type")"
else
@@ -54,7 +58,7 @@ case "$type" in
apt)
if [ -f "$apt_dist_upgrade" ]
then echo "$aptget dist-upgrade"
- else echo "$aptget upgrade"
+ else echo "$aptget $apt_with_new_pkgs upgrade"
fi
if [ -f "$apt_clean" ]
diff --git a/cdist/conf/type/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst
index e9e2b8ce..0c116bac 100644
--- a/cdist/conf/type/__package_upgrade_all/man.rst
+++ b/cdist/conf/type/__package_upgrade_all/man.rst
@@ -33,6 +33,14 @@ BOOLEAN PARAMETERS
apt-dist-upgrade
Do dist-upgrade instead of upgrade.
+apt-with-new-pkg
+ Allow installing new packages when used in conjunction with
+ upgrade. This is useful if the update of an installed package
+ requires new dependencies to be installed. Instead of holding the
+ package back upgrade will upgrade the package and install the new
+ dependencies. Note that upgrade with this option will never remove
+ packages, only allow adding new ones.
+
apt-clean
Clean out the local repository of retrieved package files.
diff --git a/cdist/conf/type/__package_upgrade_all/parameter/boolean b/cdist/conf/type/__package_upgrade_all/parameter/boolean
index 7a56a34b..cd22eb90 100644
--- a/cdist/conf/type/__package_upgrade_all/parameter/boolean
+++ b/cdist/conf/type/__package_upgrade_all/parameter/boolean
@@ -1,2 +1,3 @@
apt-clean
apt-dist-upgrade
+apt-with-new-pkgs
diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local
index be4feabb..e9f3c131 100755
--- a/cdist/conf/type/__rsync/gencode-local
+++ b/cdist/conf/type/__rsync/gencode-local
@@ -1,41 +1,104 @@
#!/bin/sh -e
-#
-# 2015 Dominique Roux (dominique.roux4 at gmail.com)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
-source=$(cat "$__object/parameter/source")
-remote_user=$(cat "$__object/parameter/remote-user")
+if ! command -v rsync > /dev/null
+then
+ echo 'rsync is missing in local machine' >&2
+ exit 1
+fi
-if [ -f "$__object/parameter/destination" ]; then
- destination=$(cat "$__object/parameter/destination")
+src="$( cat "$__object/parameter/source" )"
+
+if [ ! -e "$src" ]
+then
+ echo "$src not found" >&2
+ exit 1
+fi
+
+if [ -f "$__object/parameter/destination" ]
+then
+ dst="$( cat "$__object/parameter/destination" )"
else
- destination="/$__object_id"
+ dst="/$__object_id"
fi
-set --
-if [ -f "$__object/parameter/rsync-opts" ]; then
- while read -r opts; do
- set -- "$@" "--$opts"
- done < "$__object/parameter/rsync-opts"
+# if source is directory, then make sure that
+# source and destination are ending with slash,
+# because this is what you almost always want when
+# rsyncing two directories.
+
+if [ -d "$src" ]
+then
+ if ! echo "$src" | grep -Eq '/$'
+ then
+ src="$src/"
+ fi
+
+ if ! echo "$dst" | grep -Eq '/$'
+ then
+ dst="$dst/"
+ fi
fi
+remote_user="$( cat "$__object/parameter/remote-user" )"
+
+options="$( cat "$__object/parameter/options" )"
+
+if [ -f "$__object/parameter/option" ]
+then
+ while read -r l
+ do
+ # there's a limitation in argparse: value can't begin with '-'.
+ # to workaround this, let's prefix opts with '\' in manifest and remove here.
+ # read more about argparse issue: https://bugs.python.org/issue9334
+
+ options="$options $( echo "$l" | sed 's/\\//g' )"
+ done \
+ < "$__object/parameter/option"
+fi
+
+if [ -f "$__object/parameter/owner" ] || [ -f "$__object/parameter/group" ]
+then
+ options="$options --chown="
+
+ if [ -f "$__object/parameter/owner" ]
+ then
+ owner="$( cat "$__object/parameter/owner" )"
+ options="$options$owner"
+ fi
+
+ if [ -f "$__object/parameter/group" ]
+ then
+ group="$( cat "$__object/parameter/group" )"
+ options="$options:$group"
+ fi
+fi
+
+if [ -f "$__object/parameter/mode" ]
+then
+ mode="$( cat "$__object/parameter/mode" )"
+ options="$options --chmod=$mode"
+fi
+
+# IMPORTANT
+#
+# 1. we first dry-run rsync with change summary to find out
+# if there are any changes and code generation is needed.
+# 2. normally, to get current state or target host, we run
+# such operations in type explorers, but that's not
+# possible due to how rsync works.
+# 3. redirecting output of dry-run to stderr to ease debugging.
+# 4. to understand how that cryptic regex works, please
+# open rsync manpage and read about --itemize-changes.
+
+export RSYNC_RSH="$__remote_exec"
+
# shellcheck disable=SC2086
-echo rsync -a \
- --no-owner --no-group \
- -e \"${__remote_exec}\" \
- -q "$@" "${source}/" "${remote_user}@${__target_host}:${destination}"
+if ! rsync --dry-run --itemize-changes $options "$src" "$remote_user@$__target_host:$dst" \
+ | grep -E '^(<|>|c|h|\.|\*)[fdL][cstTpogunbax\.\+\?]+\s' >&2
+then
+ exit 0
+fi
+
+echo "export RSYNC_RSH='$__remote_exec'"
+
+echo "rsync $options $src $remote_user@$__target_host:$dst"
diff --git a/cdist/conf/type/__rsync/gencode-remote b/cdist/conf/type/__rsync/gencode-remote
deleted file mode 100755
index 074246af..00000000
--- a/cdist/conf/type/__rsync/gencode-remote
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh -e
-#
-# 2015 Dominique Roux (dominique.roux4 at gmail.com)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
-
-if [ -f "$__object/parameter/destination" ]; then
- destination=$(cat "$__object/parameter/destination")
-else
- destination="/$__object_id"
-fi
-
-ownergroup=""
-if [ -f "$__object/parameter/owner" ]; then
- ownergroup=$(cat "$__object/parameter/owner")
-fi
-if [ -f "$__object/parameter/group" ]; then
- ownergroup="${ownergroup}:$(cat "$__object/parameter/group")"
-fi
-
-if [ "$ownergroup" ]; then
- echo chown -R "$ownergroup" "$destination"
-fi
diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst
index 94b06d63..88019c92 100644
--- a/cdist/conf/type/__rsync/man.rst
+++ b/cdist/conf/type/__rsync/man.rst
@@ -3,112 +3,73 @@ cdist-type__rsync(7)
NAME
----
-cdist-type__rsync - Mirror directories using rsync
+cdist-type__rsync - Mirror directories using ``rsync``
DESCRIPTION
-----------
-WARNING: This type is of BETA quality:
-
-- it has not been tested widely
-- interfaces *may* change
-- if there is a better approach to solve the problem -> the type may even vanish
-
-If you are fine with these constraints, please read on.
-
-
-This cdist type allows you to mirror local directories to the
-target host using rsync. Rsync will be installed in the manifest of the type.
-If group or owner are giveng, a recursive chown will be executed on the
-target host.
-
-A slash will be appended to the source directory so that only the contents
-of the directory are taken and not the directory name itself.
+The purpose of this type is to bring power of ``rsync`` into ``cdist``.
REQUIRED PARAMETERS
-------------------
source
- Where to take files from
+ Source directory in local machine.
+ If source is directory, slash (``/``) will be added to source and destination paths.
OPTIONAL PARAMETERS
-------------------
-group
- Group to chgrp to.
+destination
+ Destination directory. Defaults to ``$__object_id``.
owner
- User to chown to.
+ Will be passed to ``rsync`` as ``--chown=OWNER``.
+ Read ``rsync(1)`` for more details.
-destination
- Use this as the base destination instead of the object id
+group
+ Will be passed to ``rsync`` as ``--chown=:GROUP``.
+ Read ``rsync(1)`` for more details.
+
+mode
+ Will be passed to ``rsync`` as ``--chmod=MODE``.
+ Read ``rsync(1)`` for more details.
+
+options
+ Defaults to ``--recursive --links --perms --times``.
+ Due to `bug in Python's argparse`_, value must be prefixed with ``\``.
remote-user
- Use this user instead of the default "root" for rsync operations.
+ Defaults to ``root``.
OPTIONAL MULTIPLE PARAMETERS
----------------------------
-rsync-opts
- Use this option to give rsync options with.
- See rsync(1) for available options.
- Only "--" options are supported.
- Write the options without the beginning "--"
- Can be specified multiple times.
-
-
-MESSAGES
---------
-NONE
+option
+ Pass additional options to ``rsync``.
+ See ``rsync(1)`` for all possible options.
+ Due to `bug in Python's argparse`_, value must be prefixed with ``\``.
EXAMPLES
--------
-
.. code-block:: sh
- # You can use any source directory
- __rsync /tmp/testdir \
- --source /etc
-
- # Use source from type
- __rsync /etc \
- --source "$__type/files/package"
-
- # Allow multiple __rsync objects to write to the same dir
- __rsync mystuff \
- --destination /usr/local/bin \
- --source "$__type/files/package"
-
- __rsync otherstuff \
- --destination /usr/local/bin \
- --source "$__type/files/package2"
-
- # Use rsync option --exclude
- __rsync /tmp/testdir \
- --source /etc \
- --rsync-opts exclude=sshd_conf
-
- # Use rsync with multiple options --exclude --dry-run
- __rsync /tmp/testing \
- --source /home/tester \
- --rsync-opts exclude=id_rsa \
- --rsync-opts dry-run
-
-
-SEE ALSO
---------
-:strong:`rsync`\ (1)
+ __rsync /var/www/example.com \
+ --owner root \
+ --group www-data \
+ --mode 'D750,F640' \
+ --source "$__files/example.com/www"
AUTHORS
-------
-Nico Schottelius
+Ander Punnar
COPYING
-------
-Copyright \(C) 2015 Nico Schottelius. 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.
+Copyright \(C) 2021 Ander Punnar. 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.
diff --git a/cdist/conf/type/__rsync/manifest b/cdist/conf/type/__rsync/manifest
index 9bd44c6d..64fa804e 100755
--- a/cdist/conf/type/__rsync/manifest
+++ b/cdist/conf/type/__rsync/manifest
@@ -1,21 +1,3 @@
#!/bin/sh -e
-#
-# 2015 Dominique Roux (dominique.roux4 at gmail.com)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
__package rsync
diff --git a/cdist/conf/type/__rsync/parameter/default/options b/cdist/conf/type/__rsync/parameter/default/options
new file mode 100644
index 00000000..d967b110
--- /dev/null
+++ b/cdist/conf/type/__rsync/parameter/default/options
@@ -0,0 +1 @@
+--recursive --links --perms --times
diff --git a/cdist/conf/type/__rsync/parameter/optional b/cdist/conf/type/__rsync/parameter/optional
index ac2b2390..833e9bbe 100644
--- a/cdist/conf/type/__rsync/parameter/optional
+++ b/cdist/conf/type/__rsync/parameter/optional
@@ -1,4 +1,6 @@
destination
-owner
group
+mode
+options
+owner
remote-user
diff --git a/cdist/conf/type/__rsync/parameter/optional_multiple b/cdist/conf/type/__rsync/parameter/optional_multiple
index fdb7cd88..01925a15 100644
--- a/cdist/conf/type/__rsync/parameter/optional_multiple
+++ b/cdist/conf/type/__rsync/parameter/optional_multiple
@@ -1 +1 @@
-rsync-opts
+option
diff --git a/cdist/conf/type/__sed/explorer/file b/cdist/conf/type/__sed/explorer/file
new file mode 100755
index 00000000..ec3d0fe8
--- /dev/null
+++ b/cdist/conf/type/__sed/explorer/file
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+
+if [ -f "$__object/parameter/file" ]
+then
+ file="$( cat "$__object/parameter/file" )"
+else
+ file="/$__object_id"
+fi
+
+if [ ! -e "$file" ]
+then
+ echo "$file does not exist" >&2
+ exit 1
+fi
+
+cat "$file"
diff --git a/cdist/conf/type/__sed/gencode-remote b/cdist/conf/type/__sed/gencode-remote
new file mode 100755
index 00000000..f99c5a88
--- /dev/null
+++ b/cdist/conf/type/__sed/gencode-remote
@@ -0,0 +1,58 @@
+#!/bin/sh -e
+
+if [ -f "$__object/parameter/file" ]
+then
+ file="$( cat "$__object/parameter/file" )"
+else
+ file="/$__object_id"
+fi
+
+script="$( cat "$__object/parameter/script" )"
+
+if [ "$script" = '-' ]
+then
+ script="$( cat "$__object/stdin" )"
+fi
+
+# since stdin is not available in explorer, we pull file from target with explorer
+
+file_from_target="$__object/explorer/file"
+
+sed_cmd='sed'
+
+if [ -f "$__object/parameter/regexp-extended" ]
+then
+ sed_cmd="$sed_cmd -E"
+fi
+
+# do sed dry run, diff result and if no change, then there's nothing to do
+# also redirect diff's output to stderr for debugging purposes
+
+if echo "$script" | "$sed_cmd" -f - "$file_from_target" | diff -u "$file_from_target" - >&2
+then
+ exit 0
+fi
+
+# we can't use -i, because it's not posix, so we fly with tempfile and cp
+# and we use cp because we want to preserve destination file's attributes
+
+# shellcheck disable=SC2016
+echo 'tmp="$__object/tempfile"'
+
+echo "$sed_cmd -f - '$file' > \"\$tmp\" << EOF"
+
+echo "$script"
+
+echo 'EOF'
+
+echo "cp \"\$tmp\" '$file'"
+
+# shellcheck disable=SC2016
+echo 'rm -f "$tmp"'
+
+echo 'change' >> "$__messages_out"
+
+if [ -f "$__object/parameter/onchange" ]
+then
+ cat "$__object/parameter/onchange"
+fi
diff --git a/cdist/conf/type/__sed/man.rst b/cdist/conf/type/__sed/man.rst
new file mode 100644
index 00000000..86789363
--- /dev/null
+++ b/cdist/conf/type/__sed/man.rst
@@ -0,0 +1,57 @@
+cdist-type__sed(7)
+==================
+
+NAME
+----
+cdist-type__sed - Transform text files with ``sed``
+
+
+DESCRIPTION
+-----------
+Transform text files with ``sed``.
+
+
+REQUIRED MULTIPLE PARAMETERS
+----------------------------
+script
+ ``sed`` script.
+ If ``-`` then the script is read from ``stdin``.
+
+
+OPTIONAL PARAMETERS
+-------------------
+file
+ Path to the file. Defaults to ``$__object_id``.
+
+onchange
+ Execute this command if ``sed`` changes file.
+
+
+BOOLEAN PARAMETERS
+------------------
+regexp-extended
+ Use extended regular expressions in the script.
+ Might not be supported with every ``sed`` version.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ __sed /tmp/foobar --script 's/foo/bar/'
+
+ echo 's/foo/bar/' | __sed foobar --file /tmp/foobar --script -
+
+
+AUTHORS
+-------
+Ander Punnar
+
+
+COPYING
+-------
+Copyright \(C) 2021 Ander Punnar. 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.
diff --git a/cdist/conf/type/__sed/parameter/boolean b/cdist/conf/type/__sed/parameter/boolean
new file mode 100644
index 00000000..1ad75c5d
--- /dev/null
+++ b/cdist/conf/type/__sed/parameter/boolean
@@ -0,0 +1 @@
+regexp-extended
diff --git a/cdist/conf/type/__sed/parameter/optional b/cdist/conf/type/__sed/parameter/optional
new file mode 100644
index 00000000..fa86f917
--- /dev/null
+++ b/cdist/conf/type/__sed/parameter/optional
@@ -0,0 +1,2 @@
+file
+onchange
diff --git a/cdist/conf/type/__sed/parameter/required_multiple b/cdist/conf/type/__sed/parameter/required_multiple
new file mode 100644
index 00000000..84f7e31d
--- /dev/null
+++ b/cdist/conf/type/__sed/parameter/required_multiple
@@ -0,0 +1 @@
+script
diff --git a/cdist/conf/type/__snakeoil_cert/man.rst b/cdist/conf/type/__snakeoil_cert/man.rst
index 0b547804..b0b0a2e9 100644
--- a/cdist/conf/type/__snakeoil_cert/man.rst
+++ b/cdist/conf/type/__snakeoil_cert/man.rst
@@ -38,6 +38,7 @@ cert-path
EXAMPLES
--------
.. code-block:: sh
+
__snakeoil_cert localhost-rsa \
--common-name localhost \
--key-type rsa:4096
diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote
index 61c77fb9..cbffde94 100755
--- a/cdist/conf/type/__ssh_authorized_key/gencode-remote
+++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote
@@ -40,6 +40,7 @@ if [ -f "$file" ]; then
grep -v -F -x '$line' '$file' >\$tmpfile
fi
cat "\$tmpfile" >"$file"
+rm -f "\$tmpfile"
DONE
}
diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/keys b/cdist/conf/type/__ssh_authorized_keys/explorer/keys
index cec25746..9694a64b 100755
--- a/cdist/conf/type/__ssh_authorized_keys/explorer/keys
+++ b/cdist/conf/type/__ssh_authorized_keys/explorer/keys
@@ -1,6 +1,7 @@
#!/bin/sh -e
# shellcheck disable=SC1090
+# shellcheck disable=SC1091
file="$( . "$__type_explorer/file" )"
if [ -f "$file" ]
diff --git a/cdist/conf/type/__update_alternatives/explorer/alternatives b/cdist/conf/type/__update_alternatives/explorer/alternatives
index 34aaca56..bb1619a9 100755
--- a/cdist/conf/type/__update_alternatives/explorer/alternatives
+++ b/cdist/conf/type/__update_alternatives/explorer/alternatives
@@ -1,4 +1,4 @@
#!/bin/sh -e
-update-alternatives --display "$__object_id" 2>/dev/null \
- | awk -F ' - ' '/priority [0-9]+$/ { print $1 }'
+LC_ALL=C update-alternatives --display "${__object_id:?}" 2>/dev/null \
+| awk -F ' - ' '/priority [0-9]+$/ { print $1 }'
diff --git a/cdist/conf/type/__update_alternatives/explorer/link b/cdist/conf/type/__update_alternatives/explorer/link
index 6519e7c2..d1087c75 100755
--- a/cdist/conf/type/__update_alternatives/explorer/link
+++ b/cdist/conf/type/__update_alternatives/explorer/link
@@ -18,12 +18,12 @@ for altdir in \
/var/lib/dpkg/alternatives \
/var/lib/alternatives
do
- if [ ! -f "$altdir/$__object_id" ]
+ if [ ! -f "$altdir/${__object_id:?}" ]
then
continue
fi
- link="$( awk 'NR==2' "$altdir/$__object_id" )"
+ link="$( awk 'NR==2' "$altdir/${__object_id:?}" )"
if [ -n "$link" ]
then
@@ -31,9 +31,12 @@ do
fi
done
-if [ -z "$link" ]
+if [ -z "$link" ] && [ -z "${__cdist_dry_run+dry run}" ]
then
- echo "unable to get link for $__object_id" >&2
+ # NOTE: ignore error for dry-runs because a package providing the link
+ # might be managed by another cdist object (which wasn't executed,
+ # because dry run…).
+ echo "unable to get link for ${__object_id:?}" >&2
exit 1
fi
diff --git a/cdist/conf/type/__update_alternatives/explorer/path_is b/cdist/conf/type/__update_alternatives/explorer/path_is
index fc304d5d..5cf4fa4b 100755
--- a/cdist/conf/type/__update_alternatives/explorer/path_is
+++ b/cdist/conf/type/__update_alternatives/explorer/path_is
@@ -1,11 +1,15 @@
#!/bin/sh -e
-path_is="$( update-alternatives --display "$__object_id" 2>/dev/null \
- | awk '/link currently points to/ {print $5}' )"
+path_is=$(
+ LC_ALL=C update-alternatives --display "${__object_id?}" 2>/dev/null \
+ | awk '/link currently points to/ { print $5 }')
-if [ -z "$path_is" ]
+if [ -z "$path_is" ] && [ -z "${__cdist_dry_run+dry run}" ]
then
- echo "unable to get current path for $__object_id" >&2
+ # NOTE: ignore error for dry-runs because a package providing the
+ # alternative might be managed by another cdist object (which
+ # wasn't executed, because dry run…).
+ echo "unable to get current path for ${__object_id:?}" >&2
exit 1
fi
diff --git a/cdist/conf/type/__update_alternatives/explorer/path_should_state b/cdist/conf/type/__update_alternatives/explorer/path_should_state
index 59e015c5..b74a7ee8 100755
--- a/cdist/conf/type/__update_alternatives/explorer/path_should_state
+++ b/cdist/conf/type/__update_alternatives/explorer/path_should_state
@@ -1,6 +1,6 @@
#!/bin/sh -e
-if [ -f "$( cat "$__object/parameter/path" )" ]
+if [ -f "$( cat "${__object:?}/parameter/path" )" ]
then
echo 'present'
else
diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote
index e393cdef..e91ea78f 100755
--- a/cdist/conf/type/__update_alternatives/gencode-remote
+++ b/cdist/conf/type/__update_alternatives/gencode-remote
@@ -18,37 +18,39 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
-path_is="$( cat "$__object/explorer/path_is" )"
+path_is="$( cat "${__object:?}/explorer/path_is" )"
-path_should="$( cat "$__object/parameter/path" )"
+path_should="$( cat "${__object:?}/parameter/path" )"
if [ "$path_is" = "$path_should" ]
then
exit 0
fi
-if [ "$( cat "$__object/explorer/path_should_state" )" = 'absent' ] && [ -z "$__cdist_dry_run" ]
+if [ "$( cat "${__object:?}/explorer/path_should_state" )" = 'absent' ] \
+ && [ -z "${__cdist_dry_run+dry run}" ]
then
echo "$path_should does not exist in target" >&2
exit 1
fi
-name="$__object_id"
+name=${__object_id:?}
-alternatives="$( cat "$__object/explorer/alternatives" )"
-
-if ! echo "$alternatives" | grep -Fxq "$path_should"
+if ! grep -Fxq "$path_should" "${__object:?}/explorer/alternatives"
then
- if [ ! -f "$__object/parameter/install" ]
+ if [ -f "${__object:?}/parameter/install" ]
then
+ link="$( cat "${__object:?}/explorer/link" )"
+ echo "update-alternatives --install '$link' '$name' '$path_should' 1000"
+ elif [ -z "${__cdist_dry_run+dry run}" ]
+ then
+ # NOTE: ignore error for dry-runs because a package providing the link
+ # to be installed might be managed by another cdist object (which
+ # wasn't executed, because dry run…).
echo "$path_should is not in $name alternatives." >&2
echo 'Please install missing packages or use --install to add path to alternatives.' >&2
exit 1
fi
-
- link="$( cat "$__object/explorer/link" )"
-
- echo "update-alternatives --install '$link' '$name' '$path_should' 1000"
fi
echo "update-alternatives --set '$name' '$path_should'"
diff --git a/cdist/integration.py b/cdist/integration.py
index 17b65f09..04470ea7 100644
--- a/cdist/integration.py
+++ b/cdist/integration.py
@@ -84,7 +84,7 @@ def _process_hosts_simple(action, host, manifest, verbose,
"""
if isinstance(host, str):
hosts = [host, ]
- elif isinstance(host, collections.Iterable):
+ elif isinstance(host, collections.abc.Iterable):
hosts = host
else:
raise cdist.Error('Invalid host argument: {}'.format(host))
diff --git a/cdist/log.py b/cdist/log.py
index 113f3b4c..62e457fe 100644
--- a/cdist/log.py
+++ b/cdist/log.py
@@ -36,25 +36,27 @@ import threading
logging.OFF = logging.CRITICAL + 10 # disable logging
logging.addLevelName(logging.OFF, 'OFF')
+
logging.VERBOSE = logging.INFO - 5
logging.addLevelName(logging.VERBOSE, 'VERBOSE')
-def _verbose(msg, *args, **kwargs):
- logging.log(logging.VERBOSE, msg, *args, **kwargs)
+def _verbose(self, msg, *args, **kwargs):
+ self.log(logging.VERBOSE, msg, args, **kwargs)
-logging.verbose = _verbose
+logging.Logger.verbose = _verbose
+
logging.TRACE = logging.DEBUG - 5
logging.addLevelName(logging.TRACE, 'TRACE')
-def _trace(msg, *args, **kwargs):
- logging.log(logging.TRACE, msg, *args, **kwargs)
+def _trace(self, msg, *args, **kwargs):
+ self.log(logging.TRACE, msg, *args, **kwargs)
-logging.trace = _trace
+logging.Logger.trace = _trace
class CdistFormatter(logging.Formatter):
diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py
index 09e9cc19..6bf935e8 100644
--- a/cdist/util/fsproperty.py
+++ b/cdist/util/fsproperty.py
@@ -33,7 +33,7 @@ class AbsolutePathRequiredError(cdist.Error):
return 'Absolute path required, got: {}'.format(self.path)
-class FileList(collections.MutableSequence):
+class FileList(collections.abc.MutableSequence):
"""A list that stores it's state in a file.
"""
@@ -102,7 +102,7 @@ class FileList(collections.MutableSequence):
self.__write(lines)
-class DirectoryDict(collections.MutableMapping):
+class DirectoryDict(collections.abc.MutableMapping):
"""A dict that stores it's items as files in a directory.
"""
diff --git a/docs/changelog b/docs/changelog
index 284293c1..00defc2a 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -1,6 +1,38 @@
Changelog
---------
+7.0.0: 2022-07-31
+ * Explorer machine_type: Rewrite (Dennis Camera)
+ * New type: __sed (Ander Punnar)
+ * New type: __haproxy_dualstack (Evilham and ungleich)
+ * Type __apt_update_index: Fix complaint about suite change (Matthias Stecher)
+ * Type __package_update_index: Fix complaint about suite change (Matthias Stecher)
+ * Type __package_upgrade_all: Add new --apt-with-new-pkgs argument (Evilham)
+ * Type __apt_source: Fix complaint about suite change (Matthias Stecher)
+ * Type __package_apt: Fix complaint about suite change (Matthias Stecher)
+ * Type __debconf_set_selections: Fix bug where --file was unsupported (Evilham)
+ * Types __letsencrypt_cert, __grafana_dashboard: Improve bullseye support (Evilham)
+ * Type __ssh_authorized_key: Also remove tmpfile if removing line (Mark Verboom)
+ * Type __apt_pin: Add default priority, add comment in generated files (Daniel Fancsali)
+ * Type __file: make file uploading and attribute changes more atomic (Steven Armstrong)
+ * Type __dot_file: Add support for using --file parameter (Stephan Leemburg)
+ * Type __apt_ppa: Replace custom "remove-apt-repository" with add-apt-repository -r (Romain Dartigues)
+ * Type __apt_source: Add signed-by parameter (Daniel Fancsali)
+ * Explorer: add support for checkpoint (Stephan Leemburg)
+
+6.9.8: 2021-08-24
+ * Type __rsync: Rewrite (Ander Punnar)
+ * New type: __apt_pin (Daniel Fancsali)
+ * Explorer os_version: Convert Devuan ceres to version number (Dennis Camera)
+ * Core: Fix logging bug (Dennis Camera)
+ * Build: Improve Makefile compatibility (Evilham)
+ * Type __filesystem: Support ubuntu (Joachim Desroches)
+ * Explorer os_version: Fall back to os-release/lsb-release file on Ubuntu (Dennis Camera)
+ * Explorer memory: Fix conversion of large numbers (>= 2GiB) (Dennis Camera)
+ * Type __update_alternatives: Fix dry run and non-English systems (Dennis Camera)
+ * Explorer os_version: Fix for FreeBSD < 10.0 and for legacy Mac OS X versions (Dennis Camera)
+ * Explorer os_version: Add bookworm and trixie debian code names, fallback to 99.99 for unknown code name in sid (Ander Punnar)
+
6.9.7: 2021-07-10
* New type: __postgres_conf (Beni Ruef, Dennis Camera)
* Types __postgres_*: Improve OS support and do some cleanup (Dennis Camera)
@@ -142,7 +174,7 @@ Changelog
* Type __pf_ruleset: Refactor (Kamila Součková, Evil Ham)
* Type __pf_apply: Deprecate type (Kamila Součková, Evil Ham)
* Configuration: Add notes to cdist.cfg.skeleton (Evil Ham)
- * Explorers cpu_cores, memory: Improve *BSD support (Evil Ham)
+ * Explorers cpu_cores, memory: Improve BSD support (Evil Ham)
* Core: Remove debug logging noise (Evil Ham)
6.5.4: 2020-04-11
@@ -207,7 +239,7 @@ Changelog
* Documentation: PreOS english nitpicking (Evil Ham)
* Documentation: Add installing from source with signature verification (Darko Poljak)
* Core: preos: Support top command logging options, custom conf-dir option and CDIST_PATH env var (Darko Poljak)
- * Type __start_on_boot: Docs: remove unsupported *BSD claim (Evil Ham)
+ * Type __start_on_boot: Docs: remove unsupported BSD claim (Evil Ham)
* New type: __openldap_server (Evil Ham)
6.2.0: 2019-11-30
@@ -1066,9 +1098,9 @@ Changelog
* Removed type __removeline (replaced by __line) (Nico Schottelius)
* Type __directory: Parameter --parents and --recursive are now boolean (Nico Schottelius)
* Type __package_apt, __package_luarocks, __package_opkg,
- __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd,
- __package_rubygem, __package_yum, __process:
- Parameter state accepts only "present" and "absent" (Nico Schottelius)
+ __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd,
+ __package_rubygem, __package_yum, __process:
+ Parameter state accepts only "present" and "absent" (Nico Schottelius)
* Dist: Initial support for pypi packaging (Nico Schottelius)
2.0.15: 2012-11-02
diff --git a/docs/dev/release-process.org b/docs/dev/release-process.org
new file mode 100644
index 00000000..42b4f5c5
--- /dev/null
+++ b/docs/dev/release-process.org
@@ -0,0 +1,90 @@
+* Install requirements (Alpine)
+ - apk add py3-pycodestyle shellcheck py3-sphinx py3-sphinx_rtd_theme \
+ py3-build twine
+* Ensure your gpg setup works with the email used in the git commit!
+ - For me this is nico@nico-notebook.schottelius.org
+ - Signature / id is on nb2
+* Create ~/.pypirc
+[distutils]
+ index-servers =
+ pypi
+ cdist
+
+[pypi]
+ username = __token__
+ password = ...
+
+[cdist]
+ repository = https://upload.pypi.org/legacy/
+ username = __token__
+ password = ...
+
+* Add date in docs/changelog
+* Run ./bin/cdist-build-helper
+* TODO Move to "build"
+ - python3 -m build
+* DONE git tag: when?
+CLOSED: [2022-07-31 Sun 23:58]
+** Asked during release process: ok
+* DONE Pypi error with distutils: do not use distutils anymore
+CLOSED: [2022-07-31 Sun 23:58]
+python3 setup.py sdist upload
+...
+Creating tar archive
+removing 'cdist-7.0.0' (and everything under it)
+running upload
+Submitting dist/cdist-7.0.0.tar.gz to https://upload.pypi.org/legacy/
+Upload failed (400): Invalid value for blake2_256_digest. Error: Use a valid, hex-encoded, BLAKE2 message digest.
+error: Upload failed (400): Invalid value for blake2_256_digest. Error: Use a valid, hex-encoded, BLAKE2 message digest.
+(venv2) [22:50] nb2:cdist%
+
+* DONE Pypi error with twine: fixed in twine 4.0.1
+CLOSED: [2022-07-31 Sun 23:58]
+
+Seeing:
+
+(venv2) [22:47] nb2:cdist% twine upload dist/cdist-7.0.0*
+Uploading distributions to https://upload.pypi.org/legacy/
+Traceback (most recent call last):
+ File "/usr/bin/twine", line 8, in
+ sys.exit(main())
+ File "/usr/lib/python3.10/site-packages/twine/__main__.py", line 28, in main
+ result = cli.dispatch(sys.argv[1:])
+ File "/usr/lib/python3.10/site-packages/twine/cli.py", line 68, in dispatch
+ return main(args.args)
+ File "/usr/lib/python3.10/site-packages/twine/commands/upload.py", line 197, in main
+ return upload(upload_settings, parsed_args.dists)
+ File "/usr/lib/python3.10/site-packages/twine/commands/upload.py", line 141, in upload
+ resp = repository.upload(package)
+ File "/usr/lib/python3.10/site-packages/twine/repository.py", line 189, in upload
+ resp = self._upload(package)
+ File "/usr/lib/python3.10/site-packages/twine/repository.py", line 144, in _upload
+ data = package.metadata_dictionary()
+ File "/usr/lib/python3.10/site-packages/twine/package.py", line 181, in metadata_dictionary
+ "dynamic": meta.dynamic,
+AttributeError: 'Wheel' object has no attribute 'dynamic'
+
+
+Fix:
+
+
+(venv2) [23:43] nb2:cdist% pipx run twine upload dist/*
+⚠️ twine is already on your PATH and installed at /home/nico/venv2/bin/twine. Downloading and running anyway.
+Uploading distributions to https://upload.pypi.org/legacy/
+Uploading cdist-7.0.0-py3-none-any.whl
+100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 868.6/868.6 kB • 00:04 • 221.3 kB/s
+Uploading cdist-7.0.0.tar.gz
+100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB • 00:08 • 169.3 kB/s
+
+View at:
+https://pypi.org/project/cdist/7.0.0/
+* TODO cdist web
+ - on staticweb-2022
+ - Should be moved to sftp/k8s
+
+
+ Manual steps:
+
+ ~/bin/permissions.public html/
+ rsync -a html/ staticweb.ungleich.ch:/home/services/www/nico/www.cdi.st/www/manual/7.0.0/
+ ssh staticweb.ungleich.ch "cd /home/services/www/nico/www.cdi.st/www/manual; ln -sf 7.0.0 latest"
diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst
index 18863145..390ab9ec 100644
--- a/docs/src/cdist-install.rst
+++ b/docs/src/cdist-install.rst
@@ -12,7 +12,7 @@ This is the machine from which you will configure target hosts.
* /bin/sh: A POSIX like shell (for instance bash, dash, zsh)
* Python >= 3.5
* SSH client
- * sphinx (for building html docs and/or the man pages)
+ * sphinx with the rtd theme (for building html docs and/or the man pages)
Target Hosts
~~~~~~~~~~~~
diff --git a/docs/src/cdist-scan.rst b/docs/src/cdist-scan.rst
index 064e65ff..86b7fab6 100644
--- a/docs/src/cdist-scan.rst
+++ b/docs/src/cdist-scan.rst
@@ -57,6 +57,7 @@ resolved name to stdout - if any. The script must be executable.
Simplest script:
.. code-block:: sh
+
#!/bin/sh
case "$1" in
@@ -71,6 +72,7 @@ Simplest script:
Resolving name from `PTR` DNS record:
.. code-block:: sh
+
#!/bin/sh
for cmd in dig sed; do
diff --git a/docs/src/conf.py b/docs/src/conf.py
index 47765413..a3dfafca 100644
--- a/docs/src/conf.py
+++ b/docs/src/conf.py
@@ -56,7 +56,7 @@ master_doc = 'index'
# General information about the project.
project = 'cdist'
-copyright = 'ungleich GmbH 2020'
+copyright = 'ungleich GmbH 2021'
# author = 'Darko Poljak'
# The version info for the project you're documenting, acts as replacement for